730 Stimmen

Lesen der gesamten ASCII-Datei in C++ std::string

Ich muss eine ganze Datei in den Speicher einlesen und sie in eine C++ std::string .

Wenn ich es in eine Tabelle einlesen würde char[] dann wäre die Antwort sehr einfach:

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

Jetzt möchte ich genau das Gleiche tun, aber mit einer std::string anstelle einer char[] . Ich möchte Schleifen vermeiden, d. h. ich nicht wollen:

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

Irgendwelche Ideen?

3 Stimmen

Es wird immer eine Schleife involviert sein, aber sie kann als Teil der Standardbibliothek implizit sein. Ist das akzeptabel? Warum versuchen Sie, Schleifen zu vermeiden?

8 Stimmen

Ich glaube, dass der Poster wusste, dass das Lesen von Bytes eine Schleife erfordert. Er wollte nur eine einfache, Perl-Stil schlucken gleichwertig. Dazu musste ich nur wenig Code schreiben.

0 Stimmen

Dieser Code ist fehlerhaft, für den Fall, dass std::string keinen kontinuierlichen Puffer für seine String-Daten verwendet (was erlaubt ist): stackoverflow.com/a/1043318/1602642

1114voto

Jerry Coffin Punkte 452852

Hier gibt es mehrere Möglichkeiten. Eine, die mir gefällt, verwendet einen Stringstream als Vermittler:

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

Jetzt ist der Inhalt von "file.txt" in einem String verfügbar als buffer.str() .

Eine andere Möglichkeit (die mir allerdings nicht so gut gefällt) ähnelt viel mehr Ihrem 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); 

Offiziell ist dies nicht erforderlich, um unter dem C++98- oder 03-Standard zu funktionieren (String ist nicht erforderlich, um Daten zusammenhängend zu speichern), aber in der Tat funktioniert es mit allen bekannten Implementierungen, und C++11 und später erfordern zusammenhängende Speicherung, so dass es garantiert ist, mit ihnen zu arbeiten.

Warum ich letztere auch nicht mag: Erstens, weil sie länger und schwerer zu lesen ist. Zweitens, weil es erfordert, dass man den Inhalt der Zeichenkette mit Daten initialisiert, die einen nicht interessieren, und diese Daten dann sofort überschreibt (ja, die Zeit für die Initialisierung ist normalerweise trivial im Vergleich zum Lesen, also spielt es wahrscheinlich keine Rolle, aber für mich fühlt es sich trotzdem irgendwie falsch an). Drittens bedeutet in einer Textdatei die Position X in der Datei nicht unbedingt, dass man X Zeichen lesen muss, um diesen Punkt zu erreichen - es ist nicht erforderlich, Dinge wie Zeilenendübersetzungen zu berücksichtigen. Auf realen Systemen, die solche Übersetzungen vornehmen (z.B. Windows), ist die übersetzte Form kürzer als die in der Datei (d.h. " \r\n " in der Datei wird zu " \n " in der übersetzten Zeichenfolge), so dass Sie lediglich ein wenig zusätzlichen Platz reserviert haben, den Sie nie verwenden. Auch dies ist nicht wirklich ein großes Problem, fühlt sich aber trotzdem ein wenig falsch an.

49 Stimmen

Der Dreizeiler funktioniert wie ein Zauberspruch!

110 Stimmen

Das hätte als Antwort markiert werden müssen.

40 Stimmen

Wichtiger Hinweis für einige, zumindest bei meiner Implementierung, der Dreizeiler funktioniert mindestens so gut wie die C fopen Alternative für Dateien unter 50KB. Danach scheint er schnell an Leistung zu verlieren. In diesem Fall sollten Sie einfach die zweite Lösung verwenden.

615voto

Tyler McHenry Punkte 71707

Aktualisierung: Es stellte sich heraus, dass diese Methode, obwohl sie den STL-Idiomen gut folgt, tatsächlich überraschend ineffizient ist! Tun Sie dies nicht mit großen Dateien. (Siehe: http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html )

Sie können einen Streambuf-Iterator aus der Datei erstellen und die Zeichenkette damit initialisieren:

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

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

Ich bin mir nicht sicher, woher Sie die t.open("file.txt", "r") Syntax aus. Soviel ich weiß, ist das keine Methode, die std::ifstream hat. Es sieht so aus, als hätten Sie es mit C's verwechselt. fopen .

編集する。 Beachten Sie auch die zusätzlichen Klammern um das erste Argument des String-Konstruktors. Diese sind unerlässlich . Sie verhindern das Problem, das als " lästigste Parse ", was in diesem Fall keinen Kompilierfehler verursacht, wie es normalerweise der Fall ist, sondern interessante (sprich: falsche) Ergebnisse liefert.

Nach KeithB's Punkt in den Kommentaren, hier ist ein Weg, um es zu tun, die alle den Speicher im Voraus zuweist (anstatt auf die automatische Neuzuweisung der String-Klasse verlassen):

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

5 Stimmen

Open ist definitiv eine Methode von ifstream, allerdings ist der 2. Parameter falsch. cplusplus.de/referenz/iostream/ifstream/open

1 Stimmen

Richtig. Ich sagte gerade, dass ifstream hat keine Methode mit der Signatur open(const char*, const char*)

0 Stimmen

Damit wird die explizite Schleife einfach implizit. Da der Iterator ein Vorwärts-Iterator ist, wird ein Zeichen nach dem anderen gelesen. Da es für den String-Konstruktor keine Möglichkeit gibt, die endgültige Länge zu kennen, wird es wahrscheinlich zu mehreren Zuweisungen und Kopien der Daten kommen.

97voto

mili Punkte 2834

Ich denke, der beste Weg ist die Verwendung von String Stream. einfach und schnell!!!

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

8 Stimmen

4 Stimmen

Denken Sie daran, den Stream anschließend zu schließen...

34 Stimmen

@YngveSneenLindal Oder lassen Sie den Destruktor dies automatisch tun - nutzen Sie die Vorteile von C++!

40voto

Ankit Acharya Punkte 2533

Sie finden das vielleicht in keinem Buch oder auf keiner Website, aber ich habe herausgefunden, dass es ziemlich gut funktioniert:

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

14 Stimmen

Gießen eof a (char) ist ein wenig zweifelhaft, da sie eine Art von Relevanz und Universalität suggeriert, die illusorisch ist. Für einige mögliche Werte von eof() und unterzeichnet char werden die Ergebnisse von der Implementierung bestimmt. Direktes Verwenden von z.B. char(0) / '\0' wäre robuster und ein ehrlicher Indikator für das, was passiert.

2 Stimmen

@TonyD. Guter Punkt über die Umwandlung von eof() in ein char. Ich nehme an, dass für alte Ascii-Zeichensätze die Übergabe eines negativen Wertes (msb auf 1 gesetzt) funktionieren würde. Aber die Übergabe von \0 (oder ein negativer Wert) funktioniert nicht bei breiten oder Multi-Byte-Eingabedateien.

7 Stimmen

Dies funktioniert nur, solange keine "eof"-Zeichen (z.B. 0x00, 0xff, ...) in der Datei vorhanden sind. Wenn es welche gibt, wird nur ein Teil der Datei gelesen.

7voto

madx Punkte 6169

Versuchen Sie eine dieser beiden 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
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X