Textdatei in char Array lesen, der C++ Weg
-
Das Array eines Vectors kannst du mit data() holen, die Größe mit size().
@die anderen:
Ja, ihr habt da was mehr Ahnung. Aber mein Weg ist schonmal mehr C++ als irgendein C-Kram...
-
TheWayOfCpp schrieb:
Oft sieht man C-Code der als C++-Coder verkauft wird, nun wollte ich mal fragen wie ihr eine Textdatei komplett in ein Char-Array einlesen würdet, ...
Normal - gar nicht!
TheWayOfCpp schrieb:
... so dass ihr danach eine Variabel mit der Länge und einen Zeiger auf der Char-Array habt und an weitere externe Lib-Funktionen weitergeben könnt. In C macht man das ja mit fopen, ftell, fread etc.
Aber wie sieht der C++ Weg dafür aus?
Ok - es gibt Ausnahmen
Das Wichtigste dabei ist, die Datei im binary-Mode zu öffnen, da es sich ja höchstwahrscheinlich um eine Binär-Datei handelt. Sonst würde womöglich eine Folge von "0x0D 0x0A" nach "0x0A" verwandelt werden.ifstream file("input.txt", ios_base::binary ); if( !file.is_open() ) // 95% aller Lesefehler resultieren daraus, dass die Datei nicht da ist, oder nicht so heißt, wie man meint! { cerr << "Fehler beim Oeffnen" << endl; return -2; // oder break, oder was auch immer } vector<char> bytes( (istreambuf_iterator<char>( file )), istreambuf_iterator<char>() ); const char* start = &bytes.front(); size_t anzahl = bytes.size();
-
Werner Salomon schrieb:
[code="cpp"]
vector<char> bytes( (istreambuf_iterator<char>( file )), istreambuf_iterator<char>() );Mein Code ist auf meinem Computer Faktor 10 schneller.
-
Na wenns denn unbedingt schnell sein muss:
size_t fileSize(ifstream& is) { auto curr = is.tellg(); is.seekg(0, ios_base::end); auto size = is.tellg(); is.seekg(curr); return size; } int main() { ifstream is("filename", ios_base::binary); if(!is) { // error beim oeffnen } auto size = fileSize(is); vector<uint8_t> buffer(size); if(!is.read(reinterpret_cast<char*>(buffer.data()), size)) { // error beim lesen } // success }
-
baffdofail schrieb:
Werner Salomon schrieb:
[code="cpp"]
vector<char> bytes( (istreambuf_iterator<char>( file )), istreambuf_iterator<char>() );Mein Code ist auf meinem Computer Faktor 10 schneller.
Optimierungen ausgeschaltet? Debug-STL eingeschaltet? Bloss wenige Byte als Daten genommen? Zuerst mit Werners Code von der Platte gelesen, dann mit deinem aus dem Cache? Hast du hinterher auch was mit den Daten gemacht? Letztere Frage, weil der Compiler eventuell schlau genug ist, den unbenutzten Stringstream komplett weg zu optimieren, aber vielleicht beim vector mehr Schwierigkeiten hat. Hast du auch den Code mit dem istreambuf_iterator genommen, statt istream_iterator?
Jedenfalls sollte sich das eigentlich nicht viel tun. Im Prinzip ist naemlich beides fast das gleiche, bloss dass dein Code intern einen std::string nimmt, Werners einen std::vector. Der Unterschied sollte nicht so gravierend sein.
-
SeppJ schrieb:
baffdofail schrieb:
Werner Salomon schrieb:
[code="cpp"]
vector<char> bytes( (istreambuf_iterator<char>( file )), istreambuf_iterator<char>() );Mein Code ist auf meinem Computer Faktor 10 schneller.
Optimierungen ausgeschaltet?
-O3
Debug-STL eingeschaltet?
Nö
Bloss wenige Byte als Daten genommen?
100MB von /dev/urandom in eine Datei kopiert und das als Test genommen.
Zuerst mit Werners Code von der Platte gelesen, dann mit deinem aus dem Cache?
Mehrmals hintereinander ausgeführt und den kleinsten Wert genommen.
Hast du hinterher auch was mit den Daten gemacht?
str.size() ausgegeben
Letztere Frage, weil der Compiler eventuell schlau genug ist, den unbenutzten Stringstream komplett weg zu optimieren, aber vielleicht beim vector mehr Schwierigkeiten hat.
Jo
Hast du auch den Code mit dem istreambuf_iterator genommen, statt istream_iterator?
Ja, den Code von Werner habe ich genau übernommen.
Jedenfalls sollte sich das eigentlich nicht viel tun. Im Prinzip ist naemlich beides fast das gleiche, bloss dass dein Code intern einen std::string nimmt, Werners einen std::vector. Der Unterschied sollte nicht so gravierend sein.
Bei Werners Code muss der String dauernd (jedenfalls öfters) neuen Speicher allokieren und es wird char für char rüberkopiert (ein dispatch pro char). Die Implementierung für rdbuf() ist da viel optimierter.
-
baffdofail schrieb:
Werner Salomon schrieb:
[code="cpp"]
vector<char> bytes( (istreambuf_iterator<char>( file )), istreambuf_iterator<char>() );Mein Code ist auf meinem Computer Faktor 10 schneller.
interessant - auf meiner Umgebung sind beide Varianten praktisch gleich schnell (Dual Core Windows 8.1 VS2013) Datei 1,2MByte in ca. 70ms
Was hast Du für eine Umgebung?Die Variante von Kellerautomat ist manchmal etwas schneller - der beste Wert lag dort bei 54ms.
Gruß
Werner
-
Also Faktor 10 bezieht sich auf die user-Zeit.
ls -lh big.txt -rw-r--r-- 1 XXX users 1001M Apr 23 XX:XX big.txt % time ./betform big.txt 1048576040 ./betform big.txt 0.28s user 7.19s system 99% cpu 7.476 total % time ./betform big.txt 1048576040 ./betform big.txt 0.29s user 1.52s system 99% cpu 1.807 total % time ./betform big.txt 1048576040 ./betform big.txt 0.27s user 1.29s system 99% cpu 1.562 total % time ./perform big.txt 1048576040 ./perform big.txt 2.05s user 0.24s system 99% cpu 2.291 total % time ./perform big.txt 1048576040 ./perform big.txt 2.07s user 0.18s system 99% cpu 2.255 total % time ./perform big.txt 1048576040 ./perform big.txt 2.08s user 0.22s system 99% cpu 2.302 total % time ./kelform big.txt 1048576040 ./kelform big.txt 0.08s user 0.27s system 99% cpu 0.357 total % time ./kelform big.txt 1048576040 ./kelform big.txt 0.07s user 0.28s system 99% cpu 0.354 total % time ./kelform big.txt 1048576040 ./kelform big.txt 0.05s user 0.29s system 99% cpu 0.342 total % time ./kelform2 big.txt 1048576040 ./kelform big.txt 1.84s user 0.19s system 99% cpu 2.030 total % time ./kelform2 big.txt 1048576040 ./kelform big.txt 1.83s user 0.20s system 99% cpu 2.031 total % time ./kelform2 big.txt 1048576040 ./kelform big.txt 1.80s user 0.23s system 99% cpu 2.031 totalperform:
#include <iostream> #include <algorithm> #include <vector> #include <cassert> #include <fstream> using namespace std; int main(int argc, const char *argv[]) { if (argc!=2) return !(std::cerr << "usage: " << argv[0] << " <file>\n", 1); ifstream file(argv[1], ios_base::binary ); if( !file.is_open() ) // 95% aller Lesefehler resultieren daraus, dass die Datei nicht da ist, oder nicht so heißt, wie man meint! { cerr << "Fehler beim Oeffnen" << endl; return -2; // oder break, oder was auch immer } vector<char> bytes( (istreambuf_iterator<char>( file )), istreambuf_iterator<char>() ); const char* start = &bytes.front(); size_t anzahl = bytes.size(); std::cout << anzahl << '\n'; }betform:
#include <iostream> #include <algorithm> #include <vector> #include <cassert> #include <fstream> #include <sstream> int main(int argc, const char *argv[]) { using namespace std; if (argc!=2) return !(std::cerr << "usage: " << argv[0] << " <file>\n", 1); ifstream file(argv[1], ios_base::binary ); if( !file.is_open() ) // 95% aller Lesefehler resultieren daraus, dass die Datei nicht da ist, oder nicht so heißt, wie man meint! { cerr << "Fehler beim Oeffnen" << endl; return -2; // oder break, oder was auch immer } auto str = static_cast<std::ostringstream&&>(std::ostringstream() << file.rdbuf()).str(); size_t anzahl = str.size(); std::cout << anzahl << '\n'; }kelform:
#include <iostream> #include <algorithm> #include <vector> #include <cassert> #include <fstream> using namespace std; int main(int argc, const char *argv[]) { if (argc!=2) return !(std::cerr << "usage: " << argv[0] << " <file>\n", 1); ifstream file(argv[1], ios_base::binary ); if( !file.is_open() ) // 95% aller Lesefehler resultieren daraus, dass die Datei nicht da ist, oder nicht so heißt, wie man meint! { cerr << "Fehler beim Oeffnen" << endl; return -2; // oder break, oder was auch immer } auto curr = file.tellg(); file.seekg(0, ios_base::end); auto size = file.tellg(); file.seekg(curr); vector<char> bytes(size); file.read(bytes.data(), size); const char* start = &bytes.front(); size_t anzahl = bytes.size(); std::cout << anzahl << '\n'; }kelform2:
// gleich wie kelform, nur mit: vector<char> bytes(size); std::copy_n(std::istreambuf_iterator<char>(file), bytes.size(), bytes.data());Compiler ist
g++ (GCC) 4.8.2.
-
Haette ich nicht erwartet. Ausser dass das read deutlich gewinnt. Das war klar, ich meine dass der stringstream+rdbuf hier deutlich besser abschneidet als der vector+iterator. Auf meinem System (GCC 4.8.1, uralter Intel Core 2 mit entsprechend wenig und lahmem RAM, deswegen nur 500 GB Daten) ist der Unterschied zwischen den beiden aber immerhin weniger krass (aber immerhin mehr als ich erwartet haette):
Beste Zeiten (real / Sekunden):
betform: 1.426
perform: 2.405
kelform: 0.673
kelform2: 1.574
-
Danke für die rege Beteiligung. Ich habe jetzt die kelform genommen und meinen Bedürfnissen angepasst.