Question Lire le fichier ligne par ligne


Le contenu de file.txt est:

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

5 3 est une paire de coordonnées. Comment traiter cette ligne de données par ligne en C ++?

Je peux obtenir la première ligne, mais comment puis-je obtenir la ligne suivante du fichier?

ofstream myfile;
myfile.open ("text.txt");

458
2017-10-23 20:24


origine


Réponses:


D'abord, faites un ifstream:

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

Les deux méthodes standard sont:

  1. Supposons que chaque ligne se compose de deux nombres et lit le jeton par jeton:

    int a, b;
    while (infile >> a >> b)
    {
        // process pair (a,b)
    }
    
  2. Analyse syntaxique basée sur des lignes, en utilisant des flux de chaînes:

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

Vous ne devez pas mélanger (1) et (2), car l'analyse basée sur des jetons ne contient pas de nouvelles lignes, vous pouvez donc vous retrouver avec des lignes vides si vous utilisez getline() Après l'extraction basée sur les jetons, vous êtes déjà arrivé à la fin d'une ligne.


687
2017-10-23 20:34



Utilisation ifstream lire les données d'un fichier:

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

Si vous avez vraiment besoin de lire ligne par ligne, alors faites ceci:

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

Mais vous avez probablement juste besoin d'extraire des paires de coordonnées:

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

Mettre à jour:

Dans votre code, vous utilisez ofstream myfile;, Cependant, le o dans ofstream signifie output. Si vous voulez lire à partir du fichier (input), utilisez ifstream. Si vous voulez à la fois lire et écrire, utilisez fstream.


139
2017-10-23 20:32



Puisque vos coordonnées sont regroupées en paires, pourquoi ne pas écrire une structure pour elles?

struct CoordinatePair
{
    int x;
    int y;
};

Vous pouvez ensuite écrire un opérateur d'extraction surchargé pour istreams:

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

    return is;
}

Et puis vous pouvez lire un fichier de coordonnées directement dans un vecteur comme celui-ci:

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

7
2017-08-20 16:58



En étendant la réponse acceptée, si l'entrée est:

1,NYC
2,ABQ
...

vous serez toujours capable d'appliquer la même logique, comme ceci:

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

5
2018-05-18 09:35



La lecture d'un fichier ligne par ligne en C ++ peut se faire de différentes manières.

[Rapide] Boucle avec std :: getline ()

L'approche la plus simple consiste à ouvrir un std :: ifstream et une boucle en utilisant les appels std :: getline (). Le code est propre et facile à comprendre.

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

[Rapide] Utiliser la file_description_source de Boost

Une autre possibilité est d'utiliser la bibliothèque Boost, mais le code devient un peu plus verbeux. La performance est assez similaire au code ci-dessus (Loop avec 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();
        }
    }
}

[Le plus rapide] Utiliser le code C

Si les performances sont critiques pour votre logiciel, vous pouvez envisager d'utiliser le langage C. Ce code peut être 4-5 fois plus rapide que les versions C ++ ci-dessus, voir le benchmark ci-dessous

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 - Lequel est le plus rapide?

J'ai fait quelques benchmarks de performance avec le code ci-dessus et les résultats sont intéressants. J'ai testé le code avec des fichiers ASCII contenant 100 000 lignes, 1 000 000 de lignes et 10 000 000 lignes de texte. Chaque ligne de texte contient 10 mots en moyenne. Le programme est compilé avec -O3 optimisation et sa sortie est transmise à /dev/null afin de supprimer la variable de temps d'enregistrement de la mesure. Dernier point, mais non des moindres, chaque morceau de code enregistre chaque ligne avec le code printf() fonction pour la cohérence.

Les résultats montrent le temps (en ms) que chaque morceau de code a pris pour lire les fichiers.

La différence de performance entre les deux approches C ++ est minime et ne devrait faire aucune différence dans la pratique. La performance du code C est ce qui rend la référence impressionnante et peut changer la donne en termes de vitesse.

                             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


1
2017-07-28 14:35



Bien qu'il ne soit pas nécessaire de fermer le fichier manuellement, il est préférable de le faire si la portée de la variable de fichier est plus grande:

    ifstream infile(szFilePath);

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

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

0
2018-05-01 20:11



avec des arguments de ligne de commande:

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include "print.h"

using namespace std;

int main (int argc, char *argv[]) 
{
    vector<string> list;
    ifstream in_stream;
    string line;
    in_stream.open(argv[1]);

    while(!in_stream.eof())
    {
        in_stream >> line;
        list.push_back(line);
    }
    in_stream.close();
    print(list);
    sort(list.begin(), list.end());
    print(list);
}

-3
2018-06-21 21:53