Lees het hele ASCII-bestand in C++ std::string

Ik moet een heel bestand in het geheugen lezen en in een C++ std::stringplaatsen.

Als ik het in een char[]zou moeten lezen, zou het antwoord heel eenvoudig zijn:

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 ...

Nu wil ik precies hetzelfde doen, maar met een std::stringin plaats van een char[]. Ik wil loops vermijden, d.w.z. ik nietwil:

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

Enig idee?


Antwoord 1, autoriteit 100%

Update:Het blijkt dat deze methode, hoewel ze de STL-idiomen goed volgt, eigenlijk verrassend inefficiënt is! Doe dit niet bij grote bestanden. (Zie: http://insanecoding. blogspot.com/2011/11/how-to-read-in-file-in-c.html)

Je kunt een streambuf-iterator van het bestand maken en de string ermee initialiseren:

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

Niet zeker waar u de t.open("file.txt", "r")SYNTAX VANAF KRIJGEN VAN. Voor zover ik weet, is dat geen methode die std::ifstreamheeft. Het lijkt erop dat je het verward bent met C’s fopen.

EDIT: Let ook op de extra haakjes rond het eerste argument voor de stringconstructeur. Dit zijn essentieel . Ze voorkomen het probleem dat bekend staat als de “Meest vexing parsse “, die in dit geval u in dit geval niet echt een compileerfout geeft zoals het gewoonlijk doet, maar geeft u interessant (lees: fout).

het punt van Keithb volgen in de opmerkingen, hier is een manier om het te doen die al het geheugen aan de voorkant wijst (in plaats van te vertrouwen op de automatische reallocatie van de stringklasse):

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

Antwoord 2, Autoriteit 160%

Er zijn een paar mogelijkheden. Iemand die ik leuk vind, gebruikt een streekstroom als een tussenpersoon:

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

Nu zijn de inhoud van “file.txt” verkrijgbaar in een reeks als buffer.str().

een andere mogelijkheid (hoewel ik het zeker niet leuk vind, is het nog veel meer op uw origineel:

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

Officieel is dit niet verplicht om onder de C++ 98 of 03-standaard te werken (string is niet verplicht om gegevens aansluit op te slaan), maar in feite werkt het met alle bekende implementaties en C++ 11 en later vereisen aangrenzende opslag, dus het werkt gegarandeerd met hen.

Met betrekking tot waarom ik het laatste ook niet leuk vind: eerst, omdat het langer en moeilijker te lezen is. Ten tweede, omdat het vereist dat u de inhoud van de tekenreeks initialiseert met gegevens waar u niet om geeft, dan onmiddellijk over die gegevens (ja, de tijd om initialiseert, is meestal triviaal in vergelijking met het lezen, dus het maakt niet toe , maar voor mij voelt het nog steeds een beetje fout). Ten derde, in een tekstbestand, Position X in het bestand betekent niet noodzakelijk dat u X-tekens hebt gelezen om dat punt te bereiken – het is niet verplicht om rekening te houden met dingen zoals Line-end Translations. Op echte systemen die dergelijke vertalingen (bijv. Windows) het vertaalde formulier korter is dan wat er in het bestand is (dwz “\ r \ n” in het bestand wordt “\ n” in de vertaalde string) dus alles wat u hebt gedaan is een beetje extra ruimte gereserveerd dat je nooit gebruikt. Nogmaals, veroorzaakt niet echt een groot probleem, maar voelt toch een beetje verkeerd.


Antwoord 3, Autoriteit 13%

Ik denk dat de beste manier is om stringstream te gebruiken. eenvoudig en snel !!!

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

Antwoord 4, autoriteit 3%

Misschien vind je dit in geen enkel boek of op een site, maar ik heb ontdekt dat het redelijk goed werkt:

#include <fstream>
// ...
std::string file_content;
std::getline(std::ifstream("filename.txt"), file_content, '\0');

Antwoord 5

Probeer een van deze twee methoden:

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
}

Antwoord 6

Ik heb een andere manier bedacht die werkt met de meeste istreams, inclusief 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();
    }
}

Antwoord 7

Als u toevallig glibmm kunt proberen, kunt u GLIB :: FILE_GET_CONTENTEN .

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

Antwoord 8

Ik zou het zo kunnen doen:

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

Als dit iets is om op te fronsen, laat het me weten waarom


Antwoord 9

Ik denk niet dat je dit kunt doen zonder een expliciete of impliciete lus, zonder eerst te lezen in een char array (of een andere container) eerst en tien constructie van de tekenreeks. Als u niet de andere mogelijkheden van een string nodig hebt, kan dit worden gedaan met vector<char>op dezelfde manier als u momenteel een char *gebruikt.

Other episodes