2015-03-12 12 views
7

Sto tentando di aprire un file per l'output e aggiungerlo ad esso. Dopo averlo accodato, voglio spostare la mia posizione di output da qualche altra parte nel file e sovrascrivere i dati esistenti. A quanto ho capito, std::ios_base::app sarà forza tutte le scritture devono essere alla fine del file che è non quello che voglio fare. Pertanto, credo che std::ios_base::ate sia il flag corretto da passare a std::ofstream::open(). Tuttavia, sembra che non funziona come previsto:std :: ofstream con std :: ate non si apre alla fine

// g++ test.cpp 
// clang++ test.cpp 
// with and without -std=c++11 
#include <iostream> 
#include <fstream> 

int main() { 
    std::streampos fin, at; 
    { 
     std::ofstream initial; 
     initial.open("test", std::ios_base::out | std::ios_base::binary); 
     if (not initial.good()) { 
      std::cerr << "initial bad open" << std::endl; 
      return 1; 
     } 
     int b = 100; 
     initial.write((char*)&b, sizeof(b)); 
     initial.flush(); 
     if (not initial.good()) { 
      std::cerr << "initial write bad" << std::endl; 
      return 1; 
     } 
     fin = initial.tellp(); 
    } 
    { 
     std::ofstream check; 
     check.open("test", std::ios_base::out | std::ios_base::binary | std::ios_base::ate); 
     if (not check.good()) { 
      std::cerr << "check bad open" << std::endl; 
      return 1; 
     } 
     at = check.tellp(); 
     if (fin != at) { 
      std::cerr << "opened at wrong position!\nfin:\t" << fin << "\n" << "at:\t" << at << std::endl; 
      return 1; 
     } 
     int bb = 200; 
     check.write((char*)&bb, sizeof(bb)); 
     check.flush(); 
     if (not check.good()) { 
      std::cerr << "check write bad" << std::endl; 
      return 1; 
     } 
     at = check.tellp(); 
    } 
    if ((fin + std::streampos(sizeof(int))) != at) { 
     std::cerr << "overwrite?\nfin:\t" << fin << "\n" << "at:\t" << at << std::endl; 
     return 1; 
    } 
    return 0; 
} 

In particolare, sembra che std::ios_base::ate fa non spostare il puntatore uscita iniziale alla fine con l'esempio visto sopra. Ovviamente questo risulterebbe nella prima scrittura che sovrascriveva l'inizio del file (che è ciò che ha causato il mio problema).

Sembra che sia l'implementazione non è corretto o altro cplusplus.com è corretto ("La posizione di uscita inizia alla fine del file.") e cppreference.com è ambigua ("cercano fino alla fine del flusso subito dopo aperto ": quale stream?).

Esiste ovviamente una soluzione semplice: basta usare stream.seekp(0, std::ios_base::end).

Quindi la mia domanda è: il mio codice è errato? L'implementazione è errata? I siti di riferimento sono errati? Qualsiasi intuizione sarebbe apprezzata.

+2

http://en.cppreference.com/w/cpp/io/ basic_filebuf/aperto. Usando 'out' senza' app' o 'in' tronca. –

risposta

7

Come si può vedere dal seguente grafico in N4296 [filebuf.members]

file io

La combinazione binary | out si aprirà il file nella stdio equivalente di "wb", che sarà truncate to zero length or create binary file for writing (N1570 7.21.5.2).

quanto controintuitivo come sembra per un ofstream, è necessario aggiungere il flag in se non si desidera che il file da troncati, o app se si vuole evitare il troncamento e cercare fino alla fine del file sul ciascuno scrive

Bonus consiglio: A differenza di fstream, ifstream e ofstream verrà automaticamente o std::ios_base::in e std::ios_base::out rispettivamente con qualsiasi bandiere forniti al costruttore oa open. È inoltre possibile utilizzare l'oggetto stesso per accedere alle bandiere:

std::ofstream check("test", check.in | check.binary | check.ate); 

I controlli per good può anche essere abbreviato in if (!initial) ecc

+2

Oh derp. Questo * totalmente * ha senso ... usa il flag di input per non troncare quando c'è un piano specifico per troncare. Senso totale proprio lì. Era il problema però. Grazie :) – inetknght

Problemi correlati