2013-07-08 12 views
11

Ich habe eine Datei, die bereits einige Daten enthält (etwa 8 kB). Ich möchte etwas vom Anfang der Datei lesen und dann die Daten überschreiben, wo ich mit dem Lesen begonnen habe. Also versuche ich den folgenden Code zu verwenden:Lesen und Schreiben in die gleiche Datei mit dem gleichen fstream

std::fstream stream("filename", std::ios::in | std::ios::out | std::ios::binary); 

char byte; 
stream.read(&byte, 1); 

// stream.seekp(1); 

int bytesCount = 4096; 

auto bytesVec = std::vector<char>(bytesCount, 'c'); 
char* bytes = bytesVec.data(); 

std::cout << stream.bad() << std::endl; 

stream.write(bytes, bytesCount); 

std::cout << stream.bad() << std::endl; 

Wenn ich diesen Code ausführen, die ersten bad() kehrt false, aber die zweite kehrt true und nichts wird tatsächlich geschrieben.

Wenn ich bytesCount zu etwas kleiner als 4096 (vermutlich die Größe einiger interner Puffer) verringern, die zweite bad() gibt false zurück, aber noch nichts geschrieben wird.

Wenn ich die seekp() Zeile auskommentieren, beginnt das Schreiben zu arbeiten: bad() gibt false zurück und die Bytes werden tatsächlich geschrieben.

Warum ist die seekp() hier erforderlich? Warum funktioniert es nicht ohne es? Ist der seekp() der richtige Weg, dies zu tun?

Ich bin mit Visual Studio 2012 auf Windows 7.

Antwort

19

Sie fallen Foul von einer Beschränkung auf die Vermischung von Lese- und Schreiboperationen auf eine Datei im Update-Modus geöffnet, die die MS fstream Bibliothek erbt von aus die C <stdio.h> Implementierung.

Die C Standard (Ich zitiere C99, aber es unterscheidet sich in diesem Punkt nicht von C89) bei 7.19.5.3/6 Staaten:

Wenn eine Datei mit dem Update-Modus ('+ geöffnet Als zweites oder drittes Zeichen in der obigen Liste der Modusargumentwerte kann sowohl die Eingabe als auch die Ausgabe an dem zugeordneten Strom durchgeführt werden. Die Ausgabe darf jedoch nicht unmittelbar gefolgt von einer Eingabe ohne einen dazwischen liegenden Aufruf der fflush-Funktion oder einer Dateipositionierungsfunktion (fseek, fsetpos oder rewind) und dem Eingang nicht unmittelbar gefolgt von der Ausgabe ohne einen dazwischen liegenden Aufruf erfolgen zu einer Dateipositionierungsfunktion, es sei denn, die Eingabeoperation trifft auf end- of-file.

(meine Betonung).

So ist Ihre stream.seekp(1) Lösung, die zu einem C fseek devolviert, richtig.

Die GNU C-Bibliothek verfügt nicht über diese Standardbeschränkung, daher funktioniert Ihr Code wie angegeben wie erwartet, wenn er mit GCC erstellt wird.

Die Bibliothek MS <fstream> entspricht dem C++ - Standard, indem sie diese Einschränkung erbt. fstream s werden mit basic_filebuf<charT,traits> implementiert. In der (C++ 11) Standard Konto dieser Vorlage, bei § 27.9.1.1/2, sagt er einfach:

Die Beschränkungen für das Lesen und eine Sequenz von einem Objekt der Klasse basic_filebuf kontrolliert das Schreiben gleich sind wie zum Lesen und Schreiben mit den Standard-C-Bibliothek FILEs.

+0

Ist dies auch für C++ - Streams dokumentiert? Oder folgt MS-Implementierung nicht dem Standard in dieser Hinsicht? – svick

+0

@svick Siehe Aktualisierung. –

0

Möglicherweise möchten Sie in gebunden Ströme aussehen - http://www.cplusplus.com/reference/ios/ios/tie/

Dies ist ein Eingang jedes Mal macht, wird die Ausgabe liest automatisch gespült werden, was ich das Verhalten Ihrer Meinung nach wollen, obwohl es einen separaten Eingang erfordert und Ausgangsstrom