792 Stimmen

Datei zeilenweise lesen mit ifstream in C++

Der Inhalt von file.txt lautet wie folgt:

5 3
6 4
7 1
10 5
11 6
12 3
12 4

Donde 5 3 ist ein Koordinatenpaar. Wie kann ich diese Daten Zeile für Zeile in C++ verarbeiten?

Ich kann die erste Zeile abrufen, aber wie kann ich die nächste Zeile der Datei abrufen?

ifstream myfile;
myfile.open ("file.txt");

1156voto

Kerrek SB Punkte 445528

Erstens: Erstellen Sie eine ifstream :

#include <fstream>
std::ifstream infile("thefile.txt");

Die beiden Standardmethoden sind:

  1. Nehmen wir an, dass jede Zeile aus zwei Zahlen besteht und Token für Token gelesen wird:

    int a, b;
    while (infile >> a >> b)
    {
        // process pair (a,b)
    }
  2. Zeilenbasiertes Parsing unter Verwendung von String-Streams:

    #include <sstream>
    #include <string>
    
    std::string line;
    while (std::getline(infile, line))
    {
        std::istringstream iss(line);
        int a, b;
        if (!(iss >> a >> b)) { break; } // error
    
        // process pair (a,b)
    }

Sie sollten (1) und (2) nicht mischen, da das Token-basierte Parsing keine Zeilenumbrüche verschlingt, so dass es zu falschen Leerzeilen kommen kann, wenn Sie getline() nachdem die Token-basierte Extraktion Sie bereits an das Ende einer Zeile geführt hat.

223voto

K-ballo Punkte 79342

使用方法 ifstream um Daten aus einer Datei zu lesen:

std::ifstream input( "filename.ext" );

Wenn Sie wirklich Zeile für Zeile lesen müssen, dann tun Sie dies:

for( std::string line; getline( input, line ); )
{
    ...for each line in input...
}

Aber wahrscheinlich müssen Sie nur die Koordinatenpaare extrahieren:

int x, y;
input >> x >> y;

Aktualisierung:

In Ihrem Code verwenden Sie ofstream myfile; jedoch die o en ofstream steht für output . Wenn Sie aus der Datei lesen wollen (Eingabe), verwenden Sie ifstream . Wenn Sie sowohl lesen als auch schreiben wollen, verwenden Sie fstream .

160voto

HugoTeixeira Punkte 4153

Das zeilenweise Lesen einer Datei in C++ kann auf verschiedene Arten erfolgen.

[Fast] Schleife mit std::getline()

Der einfachste Ansatz besteht darin, einen std::ifstream zu öffnen und mit std::getline()-Aufrufen eine Schleife zu bilden. Der Code ist sauber und leicht zu verstehen.

#include <fstream>

std::ifstream file(FILENAME);
if (file.is_open()) {
    std::string line;
    while (std::getline(file, line)) {
        // using printf() in all tests for consistency
        printf("%s", line.c_str());
    }
    file.close();
}

[Fast] Boosts file_description_source verwenden

Eine andere Möglichkeit ist die Verwendung der Boost-Bibliothek, aber der Code ist dann etwas ausführlicher. Die Leistung ist dem obigen Code recht ähnlich (Schleife mit std::getline()).

#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <fcntl.h>

namespace io = boost::iostreams;

void readLineByLineBoost() {
    int fdr = open(FILENAME, O_RDONLY);
    if (fdr >= 0) {
        io::file_descriptor_source fdDevice(fdr, io::file_descriptor_flags::close_handle);
        io::stream <io::file_descriptor_source> in(fdDevice);
        if (fdDevice.is_open()) {
            std::string line;
            while (std::getline(in, line)) {
                // using printf() in all tests for consistency
                printf("%s", line.c_str());
            }
            fdDevice.close();
        }
    }
}

[Schnellste] C-Code verwenden

Wenn die Leistung Ihrer Software entscheidend ist, sollten Sie die Sprache C verwenden. Dieser Code kann 4-5 mal schneller sein als die obigen C++-Versionen, siehe Benchmark unten

FILE* fp = fopen(FILENAME, "r");
if (fp == NULL)
    exit(EXIT_FAILURE);

char* line = NULL;
size_t len = 0;
while ((getline(&line, &len, fp)) != -1) {
    // using printf() in all tests for consistency
    printf("%s", line);
}
fclose(fp);
if (line)
    free(line);

Benchmark - Wer ist schneller?

Ich habe einige Leistungsvergleiche mit dem obigen Code durchgeführt und die Ergebnisse sind interessant. Ich habe den Code mit ASCII-Dateien getestet, die 100.000 Zeilen, 1.000.000 Zeilen und 10.000.000 Zeilen Text enthalten. Jede Textzeile enthält im Durchschnitt 10 Wörter. Das Programm ist kompiliert mit -O3 Optimierung und ihre Ausgabe wird weitergeleitet an /dev/null um die Variable der Aufzeichnungszeit aus der Messung zu entfernen. Zu guter Letzt protokolliert jedes Codestück jede Zeile mit der printf() Funktion für Konsistenz.

Die Ergebnisse zeigen die Zeit (in ms), die jeder Code zum Lesen der Dateien benötigte.

Der Leistungsunterschied zwischen den beiden C++-Ansätzen ist minimal und sollte in der Praxis keinen Unterschied machen. Die Leistung des C-Codes ist das, was den Benchmark beeindruckend macht und in Bezug auf die Geschwindigkeit ein entscheidender Faktor sein kann.

                             10K lines     100K lines     1000K lines
Loop with std::getline()         105ms          894ms          9773ms
Boost code                       106ms          968ms          9561ms
C code                            23ms          243ms          2397ms

enter image description here

20voto

Da Ihre Koordinaten als Paare zusammengehören, sollten Sie eine Struktur für sie schreiben.

struct CoordinatePair
{
    int x;
    int y;
};

Dann können Sie einen überladenen Extraktionsoperator für istreams schreiben:

std::istream& operator>>(std::istream& is, CoordinatePair& coordinates)
{
    is >> coordinates.x >> coordinates.y;

    return is;
}

Und dann kann man eine Koordinatendatei direkt in einen Vektor einlesen, etwa so:

#include <fstream>
#include <iterator>
#include <vector>

int main()
{
    char filename[] = "coordinates.txt";
    std::vector<CoordinatePair> v;
    std::ifstream ifs(filename);
    if (ifs) {
        std::copy(std::istream_iterator<CoordinatePair>(ifs), 
                std::istream_iterator<CoordinatePair>(),
                std::back_inserter(v));
    }
    else {
        std::cerr << "Couldn't open " << filename << " for reading\n";
    }
    // Now you can work with the contents of v
}

10voto

gsamaras Punkte 69528

Erweitern Sie die akzeptierte Antwort, wenn die Eingabe lautet:

1,NYC
2,ABQ
...

können Sie immer noch die gleiche Logik anwenden, etwa so:

#include <fstream>

std::ifstream infile("thefile.txt");
if (infile.is_open()) {
    int number;
    std::string str;
    char c;
    while (infile >> number >> c >> str && c == ',')
        std::cout << number << " " << str << "\n";
}
infile.close();

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X