Lesen Sie die Datei Zeile für Zeile mit ifstream in C++

Lesezeit: 8 Minuten

Lesen Sie die Datei Zeile fur Zeile mit ifstream in
Herzogin

Der Inhalt von file.txt ist:

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

Woher 5 3 ist ein Koordinatenpaar. Wie verarbeite ich diese Daten Zeile für Zeile in C++?

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

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

Lesen Sie die Datei Zeile fur Zeile mit ifstream in
Kerrek SB

Machen Sie zuerst eine ifstream:

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

Die zwei Standardmethoden sind:

  1. Nehmen Sie an, dass jede Zeile aus zwei Zahlen besteht und lesen Sie Token für Token:

    int a, b;
    while (infile >> a >> b)
    {
        // process pair (a,b)
    }
    
  2. Zeilenbasiertes Parsing mit 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 tokenbasierte Parsing keine Zeilenumbrüche verschlingt, sodass Sie bei Verwendung möglicherweise mit falschen Leerzeilen enden getline() Nach der tokenbasierten Extraktion sind Sie bereits am Ende einer Zeile.

  • @EdwardKarak: Ich verstehe nicht, was “Kommas als Token” bedeutet. Kommas repräsentieren keine ganzen Zahlen.

    – Kerrek SB

    18. Oktober 2014 um 14:22 Uhr

  • Das OP hat ein Leerzeichen verwendet, um die beiden Ganzzahlen zu begrenzen. Ich wollte wissen, ob while (infile >> a >> b) funktionieren würde, wenn das OP a als Komma als Trennzeichen verwendet, denn das ist das Szenario in meinem eigenen Programm

    – Eduard Karak

    18. Oktober 2014 um 14:46 Uhr

  • @EdwardKarak: Ah, als Sie also “Token” sagten, meinten Sie “Trennzeichen”. Rechts. Mit einem Komma würden Sie sagen: int a, b; char c; while ((infile >> a >> c >> b) && (c == ','))

    – Kerrek SB

    18. Oktober 2014 um 15:25 Uhr


  • @KerrekSB: Huh. Ich habe mich geirrt. Ich wusste nicht, dass es das kann. Ich habe vielleicht einen eigenen Code, den ich umschreiben kann.

    – Markus H

    6. Januar 2015 um 15:00 Uhr

  • Zur Erläuterung der while(getline(f, line)) { } Konstrukt und bzgl. Fehlerbehandlung schaue dir bitte diesen (meinen) Artikel an: gehrcke.de/2011/06/… (Ich denke, ich muss kein schlechtes Gewissen haben, dies hier zu posten, es ist sogar etwas älter als diese Antwort).

    – Dr. Jan-Philip Gehrcke

    18. Januar 2015 um 14:15 Uhr


1647295811 437 Lesen Sie die Datei Zeile fur Zeile mit ifstream in
K-ballo

Verwenden ifstream Daten aus einer Datei 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 Sie müssen wahrscheinlich nur Koordinatenpaare extrahieren:

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

Aktualisieren:

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

  • Ihre Lösung ist etwas verbessert: Ihre Zeilenvariable ist nach dem Einlesen der Datei nicht sichtbar, im Gegensatz zur zweiten Lösung von Kerrek SB, die ebenfalls eine gute und einfache Lösung ist.

    – DanielTuzes

    23. Juli 2013 um 14:24 Uhr

  • getline ist in string sehenalso nicht vergessen #include <string>

    – mxmlnkn

    12. Juli 2017 um 23:02 Uhr

1642559110 816 Java Nur Unterverzeichnisse eines Verzeichnisses auflisten keine Dateien
Hugo Teixeira

Das Lesen einer Datei Zeile für Zeile in C++ kann auf verschiedene Arten erfolgen.

[Fast] Schleife mit std::getline()

Der einfachste Ansatz besteht darin, einen std::ifstream zu öffnen und eine Schleife mit std::getline() -Aufrufen auszuführen. Der Code ist sauber und leicht verständlich.

#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] Verwenden Sie file_description_source von Boost

Eine andere Möglichkeit besteht darin, die Boost-Bibliothek zu verwenden, aber der Code wird etwas ausführlicher. Die Leistung ist dem obigen Code ziemlich ä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();
        }
    }
}

[Fastest] Verwenden Sie C-Code

Wenn die Leistung Ihrer Software entscheidend ist, können Sie die Verwendung der Sprache C in Erwägung ziehen. Dieser Code kann 4-5 Mal schneller sein als die C++-Versionen oben, 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 Leistungsbenchmarks 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 durchschnittlich 10 Wörter. Das Programm wird mit kompiliert -O3 Optimierung und deren Ausgabe weitergeleitet wird /dev/null um die Aufzeichnungszeitvariable aus der Messung zu entfernen. Zu guter Letzt protokolliert jedes Stück Code jede Zeile mit der printf() Funktion für Konsistenz.

Die Ergebnisse zeigen die Zeit (in ms), die jeder Codeabschnitt benötigte, um die Dateien zu lesen.

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

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

Geben Sie hier die Bildbeschreibung ein

  • Was passiert, wenn Sie die Synchronisation von C++ mit C auf den Konsolenausgaben entfernen? Möglicherweise messen Sie einen bekannten Nachteil des Standardverhaltens von std::cout vs printf.

    – Benutzer4581301

    30. Juli 2018 um 20:41 Uhr

  • Danke, dass Sie diese Bedenken geäußert haben. Ich habe die Tests wiederholt und die Leistung ist immer noch die gleiche. Ich habe den Code bearbeitet, um die zu verwenden printf() Funktion in allen Fällen für Konsistenz. Ich habe es auch schon mit versucht std::cout in allen Fällen und das machte absolut keinen Unterschied. Wie ich gerade im Text beschrieben habe, geht die Ausgabe des Programms an /dev/null Die Zeit zum Drucken der Zeilen wird also nicht gemessen.

    – Hugo Teixeira

    31. Juli 2018 um 2:11 Uhr

  • Groovig. Danke. Frage mich, wo die Verlangsamung ist.

    – Benutzer4581301

    31. Juli 2018 um 4:34 Uhr

  • Hallo @HugoTeixeira, ich weiß, dass dies ein alter Thread ist, ich habe versucht, Ihre Ergebnisse zu replizieren und konnte keinen signifikanten Unterschied zwischen c und c++ feststellen github.com/simonsso/readfile_benchmarks

    – Simson

    3. Februar 2019 um 5:24 Uhr

  • @Fareanor Das ist nicht richtig. Es betrifft nur die Standard C++-Streams, std::ifstream file ist keiner von ihnen. de.cppreference.com/w/cpp/io/ios_base/sync_with_stdio

    – Benutzer202729

    15. Juni 2020 um 1:16 Uhr

Da Ihre Koordinaten als Paare zusammengehören, warum schreiben Sie nicht eine Struktur für sie?

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 können Sie eine Datei mit Koordinaten direkt in einen Vektor wie diesen einlesen:

#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
}

1647295813 700 Lesen Sie die Datei Zeile fur Zeile mit ifstream in
Gsamaras

Erweiterung der akzeptierten Antwort, wenn die Eingabe lautet:

1,NYC
2,ABQ
...

Sie können immer noch dieselbe Logik anwenden, wie folgt:

#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();

1647295814 370 Lesen Sie die Datei Zeile fur Zeile mit ifstream in
Universum

Diese Antwort gilt für Visual Studio 2017 und wenn Sie aus einer Textdatei lesen möchten, welcher Speicherort relativ zu Ihrer kompilierten Konsolenanwendung ist.

Legen Sie zuerst Ihre Textdatei (in diesem Fall test.txt) in Ihren Lösungsordner. Belassen Sie die Textdatei nach dem Kompilieren im selben Ordner wie applicationName.exe

C:\Benutzer\”Benutzername”\Quelle\Repos\”Lösungsname”\”Lösungsname”

#include <iostream>
#include <fstream>

using namespace std;
int main()
{
    ifstream inFile;
    // open the file stream
    inFile.open(".\\test.txt");
    // check if opening a file failed
    if (inFile.fail()) {
        cerr << "Error opeing a file" << endl;
        inFile.close();
        exit(1);
    }
    string line;
    while (getline(inFile, line))
    {
        cout << line << endl;
    }
    // close the file stream
    inFile.close();
}

1647295815 196 Lesen Sie die Datei Zeile fur Zeile mit ifstream in
Vijay Bansal

Es besteht zwar keine Notwendigkeit, die Datei manuell zu schließen, aber es ist eine gute Idee, dies zu tun, wenn der Gültigkeitsbereich der Dateivariablen größer ist:

    ifstream infile(szFilePath);

    for (string line = ""; getline(infile, line); )
    {
        //do something with the line
    }

    if(infile.is_open())
        infile.close();

  • Ich bin mir nicht sicher, ob dies eine Ablehnung verdient hat. OP fragte nach einer Möglichkeit, jede Zeile zu erhalten. Diese Antwort tut dies und gibt einen guten Tipp, um sicherzustellen, dass die Datei geschlossen wird. Für ein einfaches Programm ist es vielleicht nicht erforderlich, aber zumindest eine GROSSE Gewohnheit zu bilden. Es könnte vielleicht verbessert werden, indem ein paar Codezeilen hinzugefügt werden, um die einzelnen gezogenen Zeilen zu verarbeiten, aber insgesamt ist dies die einfachste Antwort auf die OP-Frage.

    – Xandor

    18. September 2019 um 18:22 Uhr

1003280cookie-checkLesen Sie die Datei Zeile für Zeile mit ifstream in C++

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy