2008-10-12 2 views
55

Ich möchte den gesamten Inhalt einer Textdatei zu einem std::string Objekt mit C++ lesen.Was ist die eleganteste Art, eine Textdatei mit C++ zu lesen?

Mit Python, kann ich schreiben:

text = open("text.txt", "rt").read() 

Es ist sehr einfach und elegant. Ich hasse hässliche Sachen, also würde ich gerne wissen - was ist die eleganteste Art, eine Textdatei mit C++ zu lesen? Danke.

+21

Wenn Sie hässliche Sachen hassen, verwenden Sie besser nicht C++: P – OregonGhost

+6

Ein Hinweis auf die Eleganz, obwohl die eleganteste Iostream Lösung wird Ihnen immer noch hässlich erscheinen, Sie können einfach in eine schöne Funktion kapseln, damit es Ihren Augen nicht weht;) – OregonGhost

+2

In Bezug auf das 'hässliche Zeug'-Argument: 'while (hugly()) enkapsulate_more();' –

Antwort

121

Es gibt viele Möglichkeiten, Sie wählen die für Sie das eleganteste ist.

in char Lesen *:

ifstream file ("file.txt", ios::in|ios::binary|ios::ate); 
if (file.is_open()) 
{ 
    file.seekg(0, ios::end); 
    size = file.tellg(); 
    char *contents = new char [size]; 
    file.seekg (0, ios::beg); 
    file.read (contents, size); 
    file.close(); 
    //... do something with it 
    delete [] contents; 
} 

In std :: string:

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

in den Vektor <char>:

std::ifstream in("file.txt"); 
std::vector<char> contents((std::istreambuf_iterator<char>(in)), 
    std::istreambuf_iterator<char>()); 

In string, mit string:

std::ifstream in("file.txt"); 
std::stringstream buffer; 
buffer << in.rdbuf(); 
std::string contents(buffer.str()); 

file.txt ist nur ein Beispiel, alles funktioniert auch für Binärdateien, stellen Sie sicher, dass Sie ios :: binary im Ifstream-Konstruktor verwenden.

+1

Ich mag deine Antwort sogar besser als meine, was ich nicht oft sage. Gut gemacht! +1 –

+7

Sie benötigen tatsächlich ein zusätzliches Klammernpaar um das erste Argument des Inhaltskonstruktors mit istreambuf_iterator <>, um zu verhindern, dass es als Funktionsdeklaration behandelt wird. –

+0

@Greg: Danke, ich habe es jetzt behoben. –

4

Sie scheinen von Eleganz als einer bestimmten Eigenschaft von "wenig Code" zu sprechen. Dies ist natürlich in gewissem Maße subjektiv. Einige würden sagen, dass das Auslassen aller Fehlerbehandlung nicht sehr elegant ist. Manche würden sagen, dass klarer und kompakter Code, den Sie sofort verstehen, elegant ist.

Schreiben Sie Ihre eigene einzeilige Funktion/Methode, die den Inhalt der Datei liest, aber es unter der Oberfläche rigoros und sicher macht und Sie beide Aspekte der Eleganz abgedeckt haben.

Alles Gute

/Robert

+3

Korollar : Eleganz ist wie Eleganz; Vorstellungen von elegantem Code unterscheiden sich zwischen Sprachen und Paradigmen.Was ein C++ - Programmierer elegant finden könnte, wäre für einen Ruby- oder Python-Programmierer entsetzlich und umgekehrt. – Rob

0

Ich mag Milans char * Weg, aber mit Std :: String.


#include <iostream> 
#include <string> 
#include <fstream> 
#include <cstdlib> 
using namespace std; 

string& getfile(const string& filename, string& buffer) { 
    ifstream in(filename.c_str(), ios_base::binary | ios_base::ate); 
    in.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit); 
    buffer.resize(in.tellg()); 
    in.seekg(0, ios_base::beg); 
    in.read(&buffer[0], buffer.size()); 
    return buffer; 
} 

int main(int argc, char* argv[]) { 
    if (argc != 2) { 
     cerr << "Usage: this_executable file_to_read\n"; 
     return EXIT_FAILURE; 
    } 
    string buffer; 
    cout << getfile(argv[1], buffer).size() << "\n"; 
} 

(mit oder ohne ios_base :: binary, je nachdem, ob Sie Zeilenumbrüche tranlated oder nicht. Sie könnten auch getfile ändern, um nur einen String zurückgeben, so dass Sie müssen nicht einen Puffer String übergeben in . Dann testen Sie, ob der Compiler die Kopie heraus optimiert bei der Rückkehr)

dies ist jedoch ein wenig besser aussehen könnte (und viel langsamer.):


#include <iostream> 
#include <string> 
#include <fstream> 
#include <cstdlib> 
using namespace std; 

string getfile(const string& filename) { 
    ifstream in(filename.c_str(), ios_base::binary); 
    in.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit); 
    return string(istreambuf_iterator<char>(in), istreambuf_iterator<char>()); 
} 

int main(int argc, char* argv[]) { 
    if (argc != 2) { 
     cerr << "Usage: this_executable file_to_read\n"; 
     return EXIT_FAILURE; 
    } 
    cout << getfile(argv[1]).size() << "\n"; 
} 
10

dort ist another thread zu diesem Thema.

Meine Lösungen aus diesem Thread (beide Einzeiler):

Das schöne (siehe Mailänder zweite Lösung):

string str((istreambuf_iterator<char>(ifs)), istreambuf_iterator<char>()); 

und schnell:

string str(static_cast<stringstream const&>(stringstream() << ifs.rdbuf()).str()); 
+0

tatsächlich ist der erste schneller, weil er direkt auf dem istream-Puffer arbeitet, und letzterer stützt sich auf den ersten, fügt jedoch einige Fehlerstatusbits hinzu. –

+0

@ t. G. Die erste verwendet eine sehr ineffiziente Kopie, um die Zeichenkette ohne vorherige Zuweisung zu konstruieren, was zu vielen Neuzuordnungen führt. Die zweite weist einen Puffer der erforderlichen Größe vor. –

+1

Ich habe es gerade mit VC++ 10 getestet. Es hängt wirklich davon ab. Es hängt von der Dateigröße ab, die erste ist schneller für kleinere Dateien und die zweite ist schneller für die größeren Dateien, was zu beweisen scheint, was Sie gesagt haben. –

1

Aber passen Sie auf, Eine C++ - Zeichenkette (oder konkreter: Eine STL-Zeichenkette) ist so wenig wie eine C-Zeichenkette, die in der Lage ist, eine Zeichenkette beliebiger Länge zu halten - natürlich nicht!

Werfen Sie einen Blick auf das Element max_size(), das Ihnen die maximale Anzahl von Zeichen gibt, die ein String enthalten kann. Dies ist eine in der Implementierung definierte Nummer und ist möglicherweise nicht auf verschiedenen Plattformen übertragbar. Visual Studio bietet einen Wert von ca. 4gigs für Strings, andere geben nur 64k an und auf 64Bit-Plattformen gibt es etwas wirklich großes! Es kommt darauf an und natürlich kommt es normalerweise zu einer bad_alloc-Ausnahme wegen Speichererschöpfung lange bevor das 4gig Limit erreicht wird ...

BTW: max_size() ist auch ein Mitglied von anderen STL-Containern! Es gibt Ihnen die maximale Anzahl von Elementen eines bestimmten Typs (für den Sie den Container eingerichtet haben), die dieser Container (theoretisch) halten kann.

Also, wenn Sie aus einer Datei von unbekannter Herkunft Lesen Sie sollen:
- seine Größe überprüfen und sicherstellen, dass es kleiner als max_size()
- Fang und Prozess bad_alloc-Ausnahmen

Und eine andere Punkt: Warum möchten Sie die Datei in eine Zeichenfolge lesen? Ich würde erwarten, es weiter zu verarbeiten, indem ich es inkrementell analysiere oder so, oder? Anstatt es in eine Zeichenkette zu lesen, können Sie es auch in einen Stringstream lesen (der im Grunde genommen nur ein syntaktischer Zucker für eine Zeichenkette ist) und die Verarbeitung durchführen. Aber dann könnte man die Verarbeitung auch direkt aus der Datei machen. Denn bei richtiger Programmierung könnte der Stringstream nahtlos durch einen Filestream ersetzt werden, d. e. durch die Datei selbst. Oder sie haben alle die gleichen Mitglieder und Operatoren und können somit nahtlos miteinander vertauscht werden!

Und für die Verarbeitung selbst: Es gibt auch eine Menge, die Sie vom Compiler automatisiert haben können! Z.B. Nehmen wir an, Sie möchten die Zeichenfolge in Token setzen. Wenn eine geeignete Vorlage definieren, die folgenden Aktionen:
- Lesen aus einer Datei (oder einer Schnur oder einem anderen Eingabestrom)
- Tokenizing den Inhalt
- alle gefundenen Token in einen STL-Container schieben
- sortieren Sie die Token alphabetisch
- Eliminierung beliebiger Doppelwerte
können alle (!!) in einer einzigen (!) Zeile von C++ - Code realisiert werden (die Vorlage selbst und die Fehlerbehandlung beiseite lassen)! Es ist nur ein Aufruf der Funktion std :: copy()! Googeln Sie einfach nach "Token Iterator" und Sie bekommen eine Vorstellung davon, was ich meine. So scheint mir das noch "eleganter" zu sein als nur aus einer Datei zu lesen ...

+0

Anmerkung: 'max_size()' ist relativ zur Größe von 'size_t' definiert, was relativ zur Bitgröße Ihrer Plattform ist.Es ist so definiert, dass eine Zeichenfolge so groß ist, wie Ihre Plattform adressieren kann. –

Verwandte Themen