ofstream schreibt nicht alles in die Datei
-
Hallo. Ich versuche gerade ein Programm zu schreiben, dass den ofstream benutzt um eine (binäre) Datei zu erzeugen. Allerdings wird nicht alles, was in die Datei geschrieben werden soll auch tatsächlich geschrieben. Ich erzeuge den Stream so:
ofstream x("C:\\Users\\Tobbi\\Documents\\test\\xxx.zap",ios_base::out|ios_base::binary);Anschließend übergebe ich einen Zeiger auf den Stream an eine Klasse, die ihn in manchen Funktionen verwendet, die den Zeiger zum Teil wiederum an andere Klassen übergeben. Überhaupt nicht zu funktionieren scheint es in der Funktion copystream. Sie soll eine bestimmte Anzahl von Bytes von einem Stream in den anderen kopieren, wobei das benutzte Byte-Array recht groß ist, aber trotzdem noch in den Speicher passt:
void copyStream(ifstream * instream, ofstream * outstream, int byteCount){ if (byteCount==0){ return; } MEMORYSTATUS * memInfo = new MEMORYSTATUS(); GlobalMemoryStatus(memInfo); unsigned long max = (long long)((long long)memInfo->dwAvailPageFile + 2*(long long)memInfo->dwAvailPhys)/9; delete memInfo; signed int bufferSize; if (max>byteCount){ // 2.147.483.647 ist der größtmöglichste Integerwert - und leider wird ( signed ) integer von istream.get als Parameter für die Buffergröße erwartet. bufferSize = byteCount; }else{ bufferSize = max; } //ifstream inBox(FileName.c_str(),ifstream::in | ifstream::binary); char *buffer = new char[bufferSize]; //int length = filesize(instream); long pos = bufferSize; while(pos <= byteCount){ pos += bufferSize; instream->read(buffer, bufferSize); outstream->write(buffer, bufferSize); } if (pos!=byteCount){ int restSize = byteCount - (pos - bufferSize); instream->read(buffer, restSize); outstream->write(buffer, restSize); } delete[] buffer; //inBox.close(); }Besonders rätselhaft finde ich allerdings das hier:
void writeShortString(AnsiString Text, ofstream * stream){ char * data = Text.c_str(); unsigned char * len = 0; unsigned char xxx = Text.Length(); len = &xxx; stream->write(len,1); stream->write(data,*len); }Es ist eindeutig so, dass das schreiben hier manchmal klappt und manchmal nicht.
Weiß jemand, was ich falsch mache / wie ich es richtig machen kann? Schon mal Danke im vorraus für eure Tipps!
Tobbi
-
Was genau geht denn nicht? Kommt eine Exception? Sind die Daten fehlerhaft?
Generelle Anmerkung: Es ist nicht unbedingt zu empfehlen zu viel Speicher am Stück zu allokieren.
Du darfst nicht vergessen, dass du mit einer einmaligen new / malloc Anweisung das System dazu zwingst die entsprechende Byte Anzahl am Stück für dich zu reservieren. Das kann bei fast 2 GByte dann schon ziemlich schwierig werden, insbesondere bei hoher Speicherfragmentierung.Es ist definitiv sinnvoller in solchen Fällen einen Puffer mit mehreren Pages zu verwenden.
Performance Vorteile hast du da auch nicht, da deine Platte sowieso maximal die Cluster-Größe (WinDefault = 4096 Byte) pro Lesevorgang einliest.Tobbi schrieb:
while(pos <= byteCount){ pos += bufferSize; instream->read(buffer, bufferSize); outstream->write(buffer, bufferSize); } if (pos!=byteCount){ int restSize = byteCount - (pos - bufferSize); instream->read(buffer, restSize); outstream->write(buffer, restSize); }Denk mal darüber nach zu was du dein System da zwingst. Ist es wirklich nötig so viel von der Datei im Speicher zu halten?
Nochmal: Deine Festplatte liest u. schreibt max. die Cluter-Größe pro Lese-/Schreibvorgang ein/raus. Es macht also gar keinen Sinn mehr als die Cluster-Größe als Puffer zu allokieren:#include <fstream> using std::ifstream; using std::ofstream; using std::ios_base; const size_t BUF_SIZE = 4096 * 4; // kleinerer Puffer | vielfaches der ClusterGröße; void CopyStream(ifstream& in, ofstream& out, int count) { unsigned pos = 0; char* buf = new char[BUF_SIZE](); if( count == -1 ) { count = in.seekg(0, ios_base::end).tellg(); in.seekg(0, ios_base::beg); } while( !in.eof() && pos < count ) { out.write(buf, in.read(buf, BUF_SIZE).gcount()); pos += BUF_SIZE; } delete[] buf; } int main() { const char *IN_FILE = "", *OUT_FILE = ""; CopyStream(ifstream(IN_FILE, ios_base::binary), ofstream(OUT_FILE, ios_base::binary), -1); return 0; }
-
Nein, es kommt keine Exception. Die Daten, die in die Datei geschrieben werden sollen, sind einfach in der Ausgabedatei einfach nur teilweise vorhanden! Es sieht fast so aus, als ob die Datei bis zu einem bestimmten Punkt (38 Bytes) ordnungsgemäß erstellt worden wäre und dann nichts mehr geschrieben wurde, ich muss sie mir mit einem Hex-Editor noch einmal genauer angucken.
Ist es möglich, dass das Problem am Borland C++ Builder liegt? Ich benutze die Version 6.0 zusammen mit Windows 7. (Ohne irgendwelche kompatibilitätsmodi). Schließlich konnte ich ihn unter win7 auch nur schwierig zum Laufen kriegen. Wenn es tatsächlich daran liegen würde, dann würde mich das allerdings schon ziemlich wundern, da bis jetzt alles ausgezeichnet geklappt hat.Danke für den Hinweis mit der Puffergröße. Ist jetzt die Frage, wie ich an die Cluster-größe des PCs komme (windows.h ?) oder ob es nicht doch mehr Sinn macht, die Standart-Clustergröße als Konstante im Code einzubauen. Ich denke Zweiteres wäre hier wohl einfacher und so viele Anwender ändern den Standartwert sicher nicht. Wenn man den Wert aber wirklich nur einfach aus der Win-Api auslesen muss, dann ist die erste Methode effizienter auf PCs, die "anders eingestellt sind". Fragt sich nur, ob das dann wirklich soo einen großen Unterschied macht...
Tobbi
-
-
Ok. Ich habe die Funktion jetzt noch einmal neu geschrieben. Hat leider etwas gedauert, da ich momentan noch gleichzeitig an einem anderem Projekt arbeite. Damit ist jetzt auch mein Problem gelöst, auch wenn ich immernoch nicht verstehe, warum das nicht geklappt hat. Auch das, was ich in anderen Funktionen in die Datei schreibe und damit eigentlich gar nichts zu tun hat, taucht auch in der Datei auf. Es sind zwar noch einige andere logische Fehler in meinem Code, aber die sollten jetzt recht einfach zu finden/verbessern sein.
Hier der Code zur neuen Funktion, vielleicht hilft er ja jemandem... :
void copyStream(ifstream * instream, ofstream * outstream,unsigned int byteCount){ unsigned long sectors_per_cluster = 0; unsigned long bytes_per_sector = 0; unsigned long unwichtig = 0; GetDiskFreeSpaceA(0, §ors_per_cluster, &bytes_per_sector, &unwichtig, &unwichtig); unsigned long bufferSize = 4 * bytes_per_sector * sectors_per_cluster; char *buffer = new char[bufferSize]; while (byteCount > bufferSize ){ instream->read(buffer, bufferSize); outstream->write(buffer, bufferSize); byteCount -= bufferSize; } instream->read(buffer, byteCount); outstream->write(buffer, byteCount); delete[] buffer; }