web-dev-qa-db-fra.com

Lit le fichier ASCII entier en C ++ std :: string

J'ai besoin de lire un fichier entier en mémoire et de le placer dans un C++ std::string.

Si je devais le lire dans un char[], la réponse serait très simple:

std::ifstream t;
int length;
t.open("file.txt");      // open input file
t.seekg(0, std::ios::end);    // go to the end
length = t.tellg();           // report location (this is the length)
t.seekg(0, std::ios::beg);    // go back to the beginning
buffer = new char[length];    // allocate memory for a buffer of appropriate dimension
t.read(buffer, length);       // read the whole file into the buffer
t.close();                    // close file handle

// ... Do stuff with buffer here ...

Maintenant, je veux faire exactement la même chose, mais en utilisant un std::string au lieu d'un char[]. Je veux éviter les boucles, c'est-à-dire que je ne pas veux:

std::ifstream t;
t.open("file.txt");
std::string buffer;
std::string line;
while(t){
std::getline(t, line);
// ... Append line to buffer and go on
}
t.close()

Des idées?

551
Escualo

Mise à jour: Il s'avère que cette méthode, si elle suit bien les idiomes STL, est en fait étonnamment inefficace! Ne faites pas cela avec de gros fichiers. (Voir: http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html )

Vous pouvez créer un itérateur streambuf à partir du fichier et initialiser la chaîne avec:

#include <string>
#include <fstream>
#include <streambuf>

std::ifstream t("file.txt");
std::string str((std::istreambuf_iterator<char>(t)),
                 std::istreambuf_iterator<char>());

Vous ne savez pas d'où provient la syntaxe t.open("file.txt", "r"). Autant que je sache, ce n'est pas une méthode que std::ifstream a. Il semble que vous ayez confondu cela avec le fopen de C.

Edit: Notez également les parenthèses supplémentaires entourant le premier argument du constructeur de chaînes. Celles-ci sont essentielles . Ils empêchent le problème connu sous le nom de " analyse la plus frustrante ", qui dans ce cas ne vous donnera pas une erreur de compilation comme il le fait habituellement, mais vous donnera des résultats intéressants (lu: faux).

Après l’observation de KeithB dans les commentaires, voici une façon de le faire qui alloue toute la mémoire en amont (au lieu de compter sur la réallocation automatique de la classe string):

#include <string>
#include <fstream>
#include <streambuf>

std::ifstream t("file.txt");
std::string str;

t.seekg(0, std::ios::end);   
str.reserve(t.tellg());
t.seekg(0, std::ios::beg);

str.assign((std::istreambuf_iterator<char>(t)),
            std::istreambuf_iterator<char>());
493
Tyler McHenry

Il y a plusieurs possibilités. Je préfère utiliser un stringstream comme intermédiaire:

std::ifstream t("file.txt");
std::stringstream buffer;
buffer << t.rdbuf();

Maintenant, le contenu de "file.txt" est disponible dans une chaîne sous la forme buffer.str().

Une autre possibilité (même si je ne l'aime certainement pas aussi) ressemble beaucoup à votre original:

std::ifstream t("file.txt");
t.seekg(0, std::ios::end);
size_t size = t.tellg();
std::string buffer(size, ' ');
t.seekg(0);
t.read(&buffer[0], size); 

Officiellement, il n'est pas nécessaire que cela fonctionne avec la norme C++ 98 ou 03 (la chaîne n'est pas obligée de stocker des données de manière contiguë), mais elle fonctionne en fait avec toutes les implémentations connues. C++ 11 et les versions ultérieures requièrent un stockage contigu. , il est donc garanti de travailler avec eux.

Quant à la raison pour laquelle je n'aime pas ce dernier aussi: d'abord parce que c'est plus long et plus difficile à lire. Deuxièmement, comme il faut initialiser le contenu de la chaîne avec des données qui ne vous intéressent pas, puis l'écrire immédiatement (oui, le temps pour initialiser est généralement trivial par rapport à la lecture, ce qui n'a probablement pas d'importance , mais pour moi, on se sent toujours un peu mal). Troisièmement, dans un fichier texte, la position X dans le fichier ne signifie pas nécessairement que vous aurez lu les caractères X pour atteindre ce point. Il n'est pas nécessaire de prendre en compte des éléments tels que les traductions de fin de ligne. Sur les systèmes réels qui font de telles traductions (Windows, par exemple), la forme traduite est plus courte que ce qui est dans le fichier (c'est-à-dire que "\ r\n" dans le fichier devient "\ n" dans la chaîne traduite). est réservé un petit espace supplémentaire que vous n'utilisez jamais. Encore une fois, ne cause pas vraiment de problème majeur, mais se sent un peu mal de toute façon.

743
Jerry Coffin

Je pense que le meilleur moyen est d'utiliser un flux de chaîne. simple et rapide !!!

#include <fstream>
#include <iostream>
#include <sstream> //std::stringstream
int main() {
    std::ifstream inFile;
    inFile.open("inFileName"); //open the input file

    std::stringstream strStream;
    strStream << inFile.rdbuf(); //read the file
    std::string str = strStream.str(); //str holds the content of the file

    std::cout << str << "\n"; //you can do anything with the string!!!
}
62
mili

Vous ne trouverez peut-être cela dans aucun livre ni site, mais j’ai découvert que cela fonctionnait plutôt bien:

ifstream ifs ("filename.txt");
string s;
getline (ifs, s, (char) ifs.eof());
11
Ankit Acharya

Essayez l'une de ces deux méthodes:

string get_file_string(){
    std::ifstream ifs("path_to_file");
    return string((std::istreambuf_iterator<char>(ifs)),
                  (std::istreambuf_iterator<char>()));
}

string get_file_string2(){
    ifstream inFile;
    inFile.open("path_to_file");//open the input file

    stringstream strStream;
    strStream << inFile.rdbuf();//read the file
    return strStream.str();//str holds the content of the file
}
6
madx

J'ai trouvé une autre façon de fonctionner avec la plupart des istreams, y compris std :: cin!

std::string readFile()
{
    stringstream str;
    ifstream stream("Hello_World.txt");
    if(stream.is_open())
    {
        while(stream.peek() != EOF)
        {
            str << (char) stream.get();
        }
        stream.close();
        return str.str();
    }
}
2
yash101

Si vous utilisez glibmm , vous pouvez essayer Glib :: file_get_contents .

#include <iostream>
#include <glibmm.h>

int main() {
    auto filename = "my-file.txt";
    try {
        std::string contents = Glib::file_get_contents(filename);
        std::cout << "File data:\n" << contents << std::endl;
    catch (const Glib::FileError& e) {
        std::cout << "Oops, an error occurred:\n" << e.what() << std::endl;
    }

    return 0;
}
1
Artem Vorotnikov

Je pourrais le faire comme ça:

void readfile(const std::string &filepath,std::string &buffer){
    std::ifstream fin(filepath.c_str());
    getline(fin, buffer, char(-1));
    fin.close();
}

Si ceci est quelque chose à être mal vu, s'il vous plaît laissez-moi savoir pourquoi

0
chunkyguy