web-dev-qa-db-fra.com

Lire le fichier ligne par ligne en utilisant ifstream en C ++

Le contenu de fichier.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 ces données ligne par ligne en C++?

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

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

Commencez par créer 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 lise jeton par jeton:

    int a, b;
    while (infile >> a >> b)
    {
        // process pair (a,b)
    }
    
  2. Analyse basée sur les lignes, à l'aide de 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 devriez pas mélanger (1) et (2), étant donné que l'analyse basée sur les jetons n'emballe pas de nouvelles lignes, vous pouvez donc vous retrouver avec de fausses lignes vides si vous utilisez getline() après l'extraction basée sur les jetons. à la fin d'une ligne déjà.

836
Kerrek SB

Utilisez ifstream pour lire les données d’un fichier:

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

Si vous avez vraiment besoin de lire ligne par ligne, procédez comme suit:

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

Mais vous devez probablement simplement extraire des paires de coordonnées:

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

Mise à jour:

Dans votre code, vous utilisez ofstream myfile;, cependant le o dans ofstream signifie output. Si vous voulez lire le fichier (entrée), utilisez ifstream. Si vous voulez lire et écrire, utilisez fstream.

162
K-ballo

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

[Fast] Boucle avec std :: getline ()

La méthode la plus simple consiste à ouvrir un fichier std :: ifstream et une boucle à l'aide d'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é consiste à utiliser la bibliothèque Boost, mais le code devient un peu plus détaillé. 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] Utilisez le code C

Si les performances sont essentielles pour votre logiciel, vous pouvez utiliser le langage C. Ce code peut être 4-5 fois plus rapide que les versions C++ ci-dessus, voir repère 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 effectué des tests de performances 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 lignes et 10 000 000 lignes de texte. Chaque ligne de texte contient 10 mots en moyenne. Le programme est compilé avec l’optimisation -O3 et sa sortie est transmise à /dev/null afin de supprimer la variable de temps d’enregistrement de la mesure. Enfin, chaque élément de code enregistre chaque ligne avec la fonction printf() par souci de cohérence.

Les résultats indiquent le temps (en ms) nécessaire à chaque morceau de code pour lire les fichiers.

La différence de performance entre les deux approches C++ est minime et ne devrait pas faire de 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

34
HugoTeixeira

Puisque vos coordonnées vont ensemble par paires, pourquoi ne pas leur écrire une structure?

struct CoordinatePair
{
    int x;
    int y;
};

Ensuite, vous pouvez é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 ensuite, 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
}
11
Martin Broadhurst

Développer la réponse acceptée si l'entrée est:

1,NYC
2,ABQ
...

vous pourrez toujours 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();
6
gsamaras

C'est une solution générale pour charger des données dans un programme C++ et utilise la fonction readline. Cela pourrait être modifié pour les fichiers CSV, mais le délimiteur est un espace ici.

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

Cette réponse concerne Visual Studio 2017 et si vous souhaitez lire à partir d'un fichier texte quel emplacement est relatif à votre application console compilée.

commencez par placer votre fichier texte (test.txt dans ce cas) dans le dossier de votre solution. Après la compilation, conservez le fichier texte dans le même dossier que applicationName.exe.

C:\Utilisateurs\"nom d'utilisateur"\source\repos\"nom de solution"\"nom de solution"

#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