2013-07-08 19 views
11

Ho un file che contiene già alcuni dati (ad esempio, 8 kB). Voglio leggere qualcosa dall'inizio del file e quindi sovrascrivere i dati che iniziano dove ho finito di leggere. Quindi cerco di utilizzare il seguente codice:Leggere e scrivere sullo stesso file usando lo stesso flusso

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; 

Se eseguo questo codice, i primi bad() rendimenti false, ma il secondo restituisce true e nulla in realtà viene scritto.

Se si riduce bytesCount a un valore inferiore a 4096 (presumibilmente la dimensione di un buffer interno), il secondo bad() restituisce false, ma non viene ancora scritto nulla.

Se si disattiva la riga seekp(), la scrittura inizia a funzionare: bad() restituisce false e i byte vengono effettivamente scritti.

Perché è necessario il numero seekp() qui? Perché non funziona senza di esso? Lo seekp() è il modo giusto per farlo?

Sto utilizzando Visual Studio 2012 su Windows 7.

risposta

19

state cadendo fallo di una restrizione sulla mescolanza di operazioni di lettura e scrivere su un file aperto in modalità aggiornamento che fstream biblioteca di MS eredita da da la sua implementazione C <stdio.h>.

Il C standard (cito C99, ma non differisce in questo punto da C89) a 7.19.5.3/6 stati:

Quando un file viene aperto con modalità di aggiornamento ('+ 'come secondo o terzo carattere nell'elenco precedente dei valori degli argomenti della modalità), sia l'input che l'output possono essere eseguiti sul flusso associato . Tuttavia, l'uscita non deve essere seguita direttamente dall'input senza una chiamata all'intervallo alla funzione fflush o a una funzione di posizionamento file (fseek, fsetpos o riavvolgimento) e l'input non deve essere seguito direttamente dall'output senza una chiamata dell'intervallo a una funzione di posizionamento file, a meno che l'operazione di immissione non incontri l'end- di file.

(il mio accento).

Quindi la vostra soluzione stream.seekp(1), che si trasforma in C fseek, è corretta.

La libreria GNU C non ha questa limitazione Standard, quindi il codice come inviato funziona come previsto quando creato con GCC.

La libreria MS <fstream> è conforme allo standard C++ per l'ereditarietà di . fstream s sono implementati utilizzando basic_filebuf<charT,traits>. Nella (C++ 11) conto di standard di questo modello, al § 27.9.1.1/2, si dice semplicemente:

Le restrizioni alla lettura e la scrittura di una sequenza controllata da un oggetto della classe basic_filebuf sono gli stessi come per leggere e scrivere con la libreria C standard FILE.

+0

È documentato anche per gli stream C++? Oppure l'implementazione della SM non segue lo standard in questo senso? – svick

+0

@svick Vedi aggiornamento. –

0

Si consiglia di guardare in flussi legati - http://www.cplusplus.com/reference/ios/ios/tie/

Questo rende ogni volta che un ingresso legge l'uscita verrà automaticamente lavato, che è credo che il comportamento che volete, anche se richiede un ingresso separato e flusso di uscita

Problemi correlati