2015-07-17 19 views
13

Qual è l'insieme corretto di flag di I/O per un std::fstream, dove voglio essere in grado di leggere da e scrivere nel file, senza troncare il file se esiste, ma creandolo se non lo è?Come posso aprire un file per leggere e scrivere, crearlo se non esiste, senza troncarlo?

Ho provato

std::ios::binary | std::ios::in | std::ios::out 
std::ios::binary | std::ios::in | std::ios::out | std::ios::ate 

ma nessuno di questi creo il file se non esiste già.

Non voglio std::ios::app, perché ho anche bisogno di essere in grado di cercare in giro per il file a piacimento, sia con il ottenere e messo cursori.

Una soluzione, suppongo, sarebbe quella di istanziare un std::ofstream prima, quindi chiuderlo immediatamente e aprire lo streaming che desidero veramente, ma ciò sembra disordinato se può essere evitato con un singolo oggetto flusso.

risposta

3

In questo momento, sto concludendo che lo stesso std::ios::in impedisce questo e che devo utilizzare la soluzione alternativa.

Quindi:

if (!std::ostream(path.c_str())) 
    throw std::runtime_error("Could not create/open file"); 

std::fstream fs(path.c_str(), std::ios::binary | std::ios::in | std::ios::out); 
if (!fs) 
    throw std::runtime_error("Could not open file"); 

// ... use `fs` 
+0

Non è necessario il controllo o la segnalazione degli errori per il tentativo di creazione. Inoltre, penso che non sia necessario usare 'c_str()' con C++ 11 e successivi. È possibile che il file system Boost faccia questo per te (non lo so), se è così allora devi solo aspettare fino a C++ 17. ;-) –

+0

@ Cheersandhth.-Alf as-tagged (C++ 03), sembra il motivo per il 'c_str()', anche se hai chiaramente ragione se qualcuno che sta leggendo lo farà con C++ 11 o più tardi. La costruzione 'std :: string' non era inclusa in 03x, btw? – WhozCraig

+0

@WhozCraig: No, l'unica novità in C++ 03 era l'inizializzazione del valore. –

-1

Prendendo std::ios::binary come letto, il restante openmode probabilmente avete bisogno è:

std::ios::in | std::ios::app 

E 'effetto è come se per aprire il file con:

std::fopen(filename,"a+") 

e l'effetto di che è:

  • aperto o, se non esiste, creare il file per la lettura e la scrittura
  • dati di scrittura alla fine del file.

Se si apre un file come std::fstream con questo openmode, non è troncato se esiste. È possibile leggere dal file, laddove i punti del puntatore tellg()\tellp() del , a condizione che ci sia qualcosa da leggere, e si può posizionare il puntatore con lo stream seekg()\seekp() per la lettura. Tuttavia, tutte le scritture saranno aggiunte alla fine del file.

Questo openmode sarà quindi adatto alla bolletta a meno che non sia necessario eseguire scritture in dati esistenti.

+0

Grazie, chiudi, ma: _ "Non voglio' std :: ios :: app', perché devo anche essere in grado di cercare il file a piacimento, con i cursori get e put. " _ –

2

Un'indagine, dal punto di vista di Linux (anche se molto di questo probabilmente vale per altri Unix):

A livello di chiamata di sistema, si vuole open(O_RDWR | O_CREAT, 0666) (ma non O_TRUNC o O_APPEND o di un gruppo di altre bandiere, anche se discutibilmente tutti i file devono essere aperti con O_CLOEXEC | O_LARGEFILE, ma non è questo il punto)

a livello di libc, non v'è alcuna stringa standard mode che implica O_CREAT senza O_TRUNC. Tuttavia, è possibile utilizzare open seguito da fdopen.

A livello di libreria C++, non esiste un modo standard per passare i flag desiderati. Tuttavia, utilizzando classi/funzioni specifiche dell'implementazione o librerie di terze parti, è possibile; vedere How to construct a c++ fstream from a POSIX file descriptor?


Personalmente, tendo a fare tutti gli I/O a anche livello di chiamata di sistema C o, dal momento che l'API è molto più gradevole ed è più prevedibile. Per l'input/output delle istanze di classe, ho i miei modelli.

Problemi correlati