Qual è il modo corretto di fare un controllo errore di 'catturare tutti' su un'operazione di uscita fstream?

StackOverflow https://stackoverflow.com/questions/2605593

  •  25-09-2019
  •  | 
  •  

Domanda

Qual è il modo corretto per verificare la presenza di un errore generale durante l'invio dei dati a un fstream?

Aggiorna : La mia preoccupazione principale riguarda alcune cose che ho sentito parlare di un ritardo tra l'uscita e tutti i dati che vengono scritti fisicamente sul disco rigido. La mia ipotesi è che il "save_file_obj << save_str" comando sarà solo inviare i dati a un qualche tipo di buffer e che il seguente controllo "if (save_file_obj.bad ())" non sarebbe alcun uso per determinare se ci fosse un sistema operativo o hardware problema. Volevo solo sapere che cosa è stato il definitivo "catch all" modo di inviare una stringa in un file e verificare per accertarsi che sia stato scritto sul disco, prima di effettuare qualsiasi seguenti azioni come la chiusura del programma.

ho il seguente codice ...

int Saver::output()
{
    save_file_handle.open(file_name.c_str());
    if (save_file_handle.is_open())
    {
        save_file_handle << save_str.c_str();

        if (save_file_handle.bad())
        {
            x_message("Error - failed to save file");
            return 0;
        }

        save_file_handle.close();

        if (save_file_handle.bad())
        {
            x_message("Error - failed to save file");
            return 0;
        }

        return 1;
    }
    else
    {
        x_message("Error - couldn't open save file");
        return 0;
    }
} 
È stato utile?

Soluzione

Tutto tranne per il controllo dopo la chiusura sembra ragionevole. Detto questo, vorrei cose ristrutturare in modo leggermente diverso e un'eccezione o utilizzare un bool, ma che è semplicemente una questione di preferenza:

bool Saver::output()
{
    std::fstream out(_filename.c_str(),std::ios::out);
    if ( ! out.is_open() ){
         LOG4CXX_ERROR(_logger,"Could not open \""<<filename<<"\"");
         return false;
    }

    out << _savestr << std::endl;
    if ( out.bad() ){
         LOG4CXX_ERROR(_logger,"Could not save to \""<<filename<<"\"");
         out.close();
         return false;
    }

    out.close();
    return true;
}

Vorrei anche sottolineare che non è necessario per l'uso save_str.c_str(), dal momento che C ++ iostreams (compresi fstream, ofstream, ecc) sono tutti in grado di emettere oggetti std :: string. Inoltre, se si costruisce l'oggetto flusso di file nel campo di applicazione della funzione, verrà automaticamente chiuso quando si va fuori del campo di applicazione.

Altri suggerimenti

Alcuni punti. In primo luogo:

save_file_handle

è un nome povero per un'istanza di un fstream C ++. fstreams non sono handle di file e tutto questo può fare è confondere il lettore.

In secondo luogo, come Michael pinte fuori, non c'è bisogno di convertire una stringa C ++ per un C-string. L'unica volta che si dovrebbe davvero trovare te fare questo è quando ci si interfaccia con le API in stile C, e quando si utilizza alcune API mal progettati C ++, come (purtroppo) fstream :: open ().

In terzo luogo, il modo canonico di test se un'operazione di flusso lavorato è quello di testare l'operazione stessa. Flussi hanno una conversione a * vuoto che significa che è possibile scrivere cose come questa:

if ( save_file_handle << save_str ) {
   // operation worked
}
else {
   // failed for some reason
}

Il codice dovrebbe sempre testv streaming operazioni, sia per ingresso o uscita.

Sei assolutamente sicuro che save_file_handle non dispone già di un file associato (aperto) con esso? Se è così allora chiamando il suo metodo open() fallirà e alzare la sua bandiera errore ios::failbit -. Ed eventuali eccezioni se impostata a farlo

Il metodo close() non può non meno che il file non è aperto, nel qual caso il metodo si alza il flag di errore ios::failbit. In ogni caso, il distruttore dovrebbe chiudere il file, e lo fanno automaticamente se il save_file_handle è una variabile stack come nel codice.

int Saver::output()
{
    save_file_handle.open(file_name.c_str());
    if (save_file_handle.fail())
    {
        x_message("Error - file failed to previously close");
        return 0;
    }
    save_file_handle << save_str.c_str();

    if (save_file_handle.bad())
    {
        x_message("Error - failed to save file");
        return 0;
    }    
    return 1;
}

In alternativa, è possibile separare il controllo degli errori dalla logica di salvataggio dei file se si utilizza ios::exceptions().

int Saver::output()
{
    ios_base::iostate old = save_file_handle.exceptions();
    save_file_handle.exceptions(ios::failbit | ios::badbit);
    try
    {
        save_file_handle.open(file_name.c_str());          
        save_file_handle << save_str.c_str();
    }
    catch (ofstream::failure e)
    {
        x_message("Error - couldn't save file");
        save_file_handle.exceptions(old);
        return 0;
    }
    save_file_handle.exceptions(old);
    return 1;
}

Si potrebbe preferire di passare la chiamata al save_file_handle.exceptions(ios::failbit | ios::badbit) al costruttore (s). Poi si può sbarazzarsi delle dichiarazioni che resettano la bandiera eccezioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top