it-swarm.com.de

Liest die Datei Zeile für Zeile mit ifstream in C ++

Der Inhalt von file.txt ist:

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

Wobei 5 3 ein Koordinatenpaar ist. Wie verarbeite ich diese Daten zeilenweise in C++?

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

ifstream myfile;
myfile.open ("text.txt");
560
dukevin

Machen Sie zuerst ein ifstream:

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

Die zwei Standardmethoden sind:

  1. Angenommen, jede Zeile besteht aus zwei Zahlen und wird Token für Token gelesen:

    int a, b;
    while (infile >> a >> b)
    {
        // process pair (a,b)
    }
    
  2. Zeilenbasiertes Parsen 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 Parsen keine Zeilenumbrüche verursacht und Sie möglicherweise falsche Leerzeilen erhalten, wenn Sie getline() nach dem Token-basierten Extrahieren verwenden schon bis zum Ende einer Zeile.

836
Kerrek SB

Verwenden Sie ifstream, um Daten aus einer Datei zu lesen:

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

Wenn Sie wirklich Zeile für Zeile lesen müssen, gehen Sie wie folgt vor:

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;

pdate:

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

162
K-ballo

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

[Fast] Schleife mit std :: getline ()

Am einfachsten ist es, einen std :: ifstream und eine Schleife mit std :: getline () -Aufrufen zu öffnen. Der Code ist sauber und leicht zu verstehen.

#include <fstream>

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

[Schnell] Verwenden Sie Boosts file_description_source

Eine andere Möglichkeit ist die Verwendung der Boost-Bibliothek, der Code wird jedoch 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();
        }
    }
}

[Am schnellsten] Verwenden Sie C-Code

Wenn die Leistung für Ihre Software kritisch ist, können Sie die Sprache C verwenden. Dieser Code kann 4-5 mal schneller sein als die oben genannten 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 - Welcher ist schneller?

Ich habe einige Leistungs-Benchmarks 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 der -O3 -Optimierung kompiliert und seine Ausgabe an /dev/null weitergeleitet, um die Protokollierungszeitvariable aus der Messung zu entfernen. Zu guter Letzt protokolliert jeder Code jede Zeile mit der Funktion printf(), um die Konsistenz zu gewährleisten.

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

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 eine entscheidende Rolle spielen.

                             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

34
HugoTeixeira

Da Ihre Koordinaten paarweise zusammengehören, schreiben Sie doch 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 Koordinatendatei 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
}
11

Erweitern Sie die akzeptierte Antwort, wenn die Eingabe wie folgt lautet:

1,NYC
2,ABQ
...

sie können dieselbe Logik wie folgt anwenden:

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

Dies ist eine allgemeine Lösung zum Laden von Daten in ein C++ - Programm und verwendet die readline-Funktion. Dies könnte für CSV-Dateien geändert werden, aber das Trennzeichen ist hier ein Leerzeichen.

int n = 5, p = 2;

int X[n][p];

ifstream myfile;

myfile.open("data.txt");

string line;
string temp = "";
int a = 0; // row index 

while (getline(myfile, line)) { //while there is a line
     int b = 0; // column index
     for (int i = 0; i < line.size(); i++) { // for each character in rowstring
          if (!isblank(line[i])) { // if it is not blank, do this
              string d(1, line[i]); // convert character to string
              temp.append(d); // append the two strings
        } else {
              X[a][b] = stod(temp);  // convert string to double
              temp = ""; // reset the capture
              b++; // increment b cause we have a new number
        }
    }

  X[a][b] = stod(temp);
  temp = "";
  a++; // onto next row
}
1
mjr2000

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 Ihrem Lösungsordner ab. Bewahren Sie die Textdatei nach dem Kompilieren im selben Ordner wie applicationName.exe auf

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();
}
1
Universus