2013-11-21 7 views
5

This answer weist darauf hin, dass C++ nicht gut für die Iteration über eine Binärdatei geeignet ist, aber das ist, was ich jetzt brauche, kurz gesagt muss ich auf Dateien "binär" arbeiten, ja alle Dateien sind binär sogar die .txt-Dateien, aber ich schreibe etwas, das mit Bilddateien arbeitet, also muss ich Dateien lesen, die gut strukturiert sind, wenn die Daten auf eine bestimmte Weise angeordnet sind.C++ - Binärdateien und Iteratoren: mit 1: 1 mit ifstreambuf_iterator wegkommen?

Ich möchte die gesamte Datei in einer Datenstruktur wie std::vector<T> lesen, so dass ich fast sofort die Datei schließen und mit dem Inhalt im Speicher arbeiten kann, ohne sich um Datenträger I/O mehr kümmern.

Gerade jetzt, der beste Weg, eine komplette Iteration über eine Datei nach der Standardbibliothek durchzuführen ist etwas entlang der Linien von

std::ifstream ifs(filename, std::ios::binary); 
    for (std::istreambuf_iterator<char, std::char_traits<char> > it(ifs.rdbuf()); 
     it != std::istreambuf_iterator<char, std::char_traits<char> >(); it++) { 
    // do something with *it; 
    } 
ifs.close(); 

oder std::copy verwenden, aber auch mit std::copy sind Sie immer mit istreambuf Iteratoren (Wenn Sie also die C++ - Dokumentation richtig verstehen, lesen Sie bei jedem Aufruf grundsätzlich 1 Byte mit dem vorherigen Code).

Die Frage ist also: Wie schreibe ich einen benutzerdefinierten Iterator? woher sollte ich erben?

Ich gehe davon aus, dass dies auch beim Schreiben einer Datei auf die Festplatte wichtig ist, und ich nehme an, dass ich die gleiche Iteratorklasse zum Schreiben verwenden könnte, wenn ich falsch liege.

+0

Ist die * Größe * der eingehenden Daten von nur ['if.read'] (http://en.cppreference.com/w/cpp/io/basic_istream/read) ausgeschlossen, so dass die Daten direkt angezeigt werden in einen 'std :: vector ' und darüber iterieren? – WhozCraig

+0

@WhozCraig für jetzt glaube ich nicht, dass die Datei zu groß sind, um im Speicher gehalten zu werden (wenn das ist, was Sie beziehen), bin ich gut mit 'lesen' oder einer anderen Möglichkeit, sogar der Konstruktor der 'vector' class unterstützt Iteratoren, also bin ich auf dieser Seite in Ordnung, das" Problem "sind die Iteratoren selbst, ich möchte eine schreiben, um zu versuchen, die Daten anders zu durchsuchen. EDIT: Ich möchte jeden C-ish-Weg vermeiden, ich bleibe bei den Iteratoren. – user2485710

+1

* Sie lesen grundsätzlich 1 Byte bei jedem Aufruf * - aus 'ifstream's Speicherpuffer, nicht aus der Datei selbst. Die tatsächlichen Lese (2) -Aufrufe sind immer noch für alle 4k oder 16k oder was auch immer der Standardpuffer für Sie ist. – Cubbi

Antwort

1

Es ist möglich, std::copy() mit std::istreambuf_iterator<char> zu optimieren, aber kaum eine Implementierung tut. Einfach von etwas abzuleiten, wird auch nicht den Trick machen, weil Iteratoren nicht so funktionieren.

Die effektivste Einbau-Ansatz ist wahrscheinlich die Datei in ein std::ostringstream und bekommen eine std::string von dort einfach Dump:

std::ostringstream out; 
out << file.rdbuf(); 
std::string content = out.str(); 

Wenn Sie einen std::string Reisen zu vermeiden, durch Sie einen Stream schreiben konnte Puffern Sie direkt den Inhalt in einen Speicherbereich oder std::vector<unsigned char> und verwenden Sie auch die obige Ausgabe.

Die std::istreambuf_iterator<char> s könnten im Prinzip eine Backdoor für die Stream-Puffer haben und chargenweise Operationen umgehen. Ohne diese Hintertür können Sie mit diesen Iteratoren nichts schneller machen. Sie könnte erstellen einen Iterator über Stream-Puffer mit dem Stream-Puffer sgetn(), um mit einem ähnlichen Puffer umzugehen. In diesem Fall benötigen Sie eine Version von std::copy(), die effizient Segmente (d. H. Jede Füllung eines Puffers) behandelt. Kurz von beiden würde ich nur die Datei in den Puffer mit einem Stream-Puffer lesen und darüber iterieren.

+0

Sie schlagen also vor, bei meiner ersten Implementierung zu bleiben? Was sind die möglichen Fehler? Was passiert, wenn die Datei beschädigt ist? – user2485710

1

Mein Vorschlag ist nicht, einen benutzerdefinierten Stream, Stream-Puffer oder Stream-Iterator zu verwenden.

#include <fstream> 

struct Data { 
    short a; 
    short b; 
    int c; 
}; 

std::istream& operator >> (std::istream& stream, Data& data) { 
    static_assert(sizeof(Data) == 2*sizeof(short) + sizeof(int), "Invalid Alignment"); 
    if(stream.read(reinterpret_cast<char*>(&data), sizeof(Data))) { 
     // Consider endian 
    } 
    else { 
     // Error 
    } 
    return stream; 
} 

int main(int argc, char* argv[]) 
{ 
    std::ifstream stream; 
    Data data; 
    while(stream >> data) { 
     // Process 
    } 
    if(stream.fail()) { 
     // Error (EOF is good) 
    } 
    return 0; 
} 

Sie es wagen könnte ein Strompuffer Iterator Leseelemente mit einer größeren Größe als die darunter liegende char_type zu machen:

  • Was ist, wenn die Daten ein ungültiges Format hat?
  • Was ist, wenn die Daten unvollständig und bei EOF sind?

Der Status des Streams wird nicht vom Puffer oder Iterator verwaltet.

+0

Ich kann die gesamte Datei puffern? – user2485710

+0

@ user2485710 Das hängt vom Pufferspeicher ab (daher ist es möglich) –