2009-11-08 11 views
6

Wenn ich eine große Binärdatei habe (sagen wir es 100.000.000 Floats), gibt es einen Weg in C (oder C++), um die Datei zu öffnen und a zu lesen spezifisches Float, ohne die ganze Datei in den Speicher laden zu müssen (dh wie kann ich schnell herausfinden, was der 62,821,214. Float ist)? Eine zweite Frage: Gibt es eine Möglichkeit, den spezifischen Float in der Datei zu ändern, ohne die gesamte Datei neu schreiben zu müssen?Lesen von und Schreiben in die Mitte einer Binärdatei in C/C++

Ich Envisioning Funktionen wie:

float readFloatFromFile(const char* fileName, int idx) { 
    FILE* f = fopen(fileName,"rb"); 

    // What goes here? 
} 

void writeFloatToFile(const char* fileName, int idx, float f) { 
    // How do I open the file? fopen can only append or start a new file, right? 

    // What goes here? 
} 
+0

Zum Schreiben, öffnen Sie im "r +" Modus und nicht "a +". Im Append-Modus, unabhängig davon, wo Sie suchen, wird immer an das Ende der Datei geschrieben. –

Antwort

19

Sie kennen die Größe eines Schwimmers ist sizeof(float), so Multiplikation können Sie in die richtige Position zu bekommen:

FILE *f = fopen(fileName, "rb"); 
fseek(f, idx * sizeof(float), SEEK_SET); 
float result; 
fread(&result, sizeof(float), 1, f); 

Ebenso können Sie schreiben zu einer bestimmten Position mit dieser Methode.

+0

Okay, großartig. Es sollte fread sein (& result, sizeof (result), 1, f); obwohl richtig? – Switch

+0

Oh, du hast recht. Ich werde das reparieren. –

4

fopen ermöglicht eine Datei für Änderung zu öffnen (nicht nur anhängen), indem entweder die rb+ oder wb+ Modus auf fopen verwenden. Siehe hier: http://www.cplusplus.com/reference/clibrary/cstdio/fopen/

Um die Datei auf einem bestimmten Schwimmer zu positionieren, können Sie die fseek unter Verwendung index*sizeof(float) als Offset ad SEEK_SET als orign verwenden können. Siehe hier: http://www.cplusplus.com/reference/clibrary/cstdio/fseek/

+0

"rb +" funktioniert, aber "wb +" schneidet die Datei ab, wenn sie existiert – marcin

3

Hier ein Beispiel ist, wenn Sie C++ Streams verwenden möchten:

#include <fstream> 
using namespace std; 

int main() 
{ 
    fstream file("floats.bin", ios::binary); 
    float number; 

    file.seekp(62821214*sizeof(float), ios::beg); 
    file.read(reinterpret_cast<char*>(&number), sizeof(float)); 
    file.seekp(0, ios::beg); // move to the beginning of the file 
    number = 3.2; 
    // write number at the beginning of the file 
    file.write(reinterpret_cast<char*>(&number), sizeof(float)); 
} 
0

Eine Möglichkeit mmap() auf die Datei zu nennen wäre. Sobald Sie das getan haben, können Sie die Datei lesen/ändern, als wäre sie ein In-Memory-Array.

Natürlich funktioniert diese Methode nur, wenn die Datei klein genug ist, um in den Adressraum Ihres Prozesses zu passen ... wenn Sie im 64-Bit-Modus laufen, wird es Ihnen gut gehen; Im 32-Bit-Modus sollte eine Datei mit 100.000.000 Gleitkommazahlen passen, aber eine oder zwei weitere Größenordnungen darüber liegen und Sie könnten in Schwierigkeiten geraten.

-1

Ich weiß, dass diese Frage bereits beantwortet wurde, aber Linux/Unix bietet einfache Systemaufrufe zum Lesen/Schreiben (pread/pwrite) in der Mitte einer Datei. Wenn Sie sich den Kernelquellcode für die Systemaufrufe 'lesen' & 'pread' anschauen, rufen beide schließlich die vfs_read() auf. Und vfs_read benötigt einen OFFSET, d.h. es erfordert eine POSITION, um aus der Datei zu lesen. In pread wird dieser Offset von uns gegeben und in read() wird der Offset intern im Kernel berechnet und für den Dateideskriptor beibehalten. pread() bietet eine außergewöhnliche Leistung im Vergleich zu read() und mit pread können Sie denselben Dateideskriptor gleichzeitig in mehreren Threads in verschiedenen Teilen der Datei lesen/schreiben. Mein Humble opionion, benutze niemals read() oder andere Dateiströme, benutze pread(). Hoffentlich haben die Filestream-Bibliotheken die read() - Aufrufe umgangen, die Streams funktionieren gut, indem sie weniger Systemaufrufe durchführen.

#include <stdio.h> 
#include <unistd.h> 
#include <fcntl.h> 
int main() 
{ 
    char* buf; off_t offToStart = id * sizeof(float); size_t sizeToRead = sizeof(float); 
    int fd = open("fileName", O_RDONLY); 
    ret = pread(fd, buf, sizeToRead, offToStart); 
    //processs from the read 'buf' 
    close(fd); 
} 
+0

kann mit dieser Lösung keine Binärdatei lesen. – LOLKFC