3

fstreamにデータを送信するときに一般的なエラーをチェックする正しい方法は何ですか?

更新:私の主な関心事は、出力とハードディスクに物理的に書き込まれるデータとの間の遅延について聞いたことがあることです。私の仮定では、コマンド「save_file_obj << save_str」はデータをある種のバッファーにのみ送信し、次のチェック「if(save_file_obj.bad())」はOSまたはハードウェアが存在するかどうかを判断するのに使用されません。問題。プログラムを閉じるなどの次のアクションを実行する前に、文字列をファイルに送信し、ディスクに書き込まれたことを確認するための最も信頼のおける「キャッチオール」方法を知りたかっただけです。

私は次のコードを持っています...

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;
    }
} 
4

3 に答える 3

5

いくつかのポイント。まず:

save_file_handle

は、C++ fstream のインスタンスの不適切な名前です。fstream はファイル ハンドルではないため、読み手を混乱させるだけです。

次に、Michael が指摘するように、C++ 文字列を C-string に変換する必要はありません。実際にこれを行う必要があるのは、C スタイルの API とやり取りするときと、(残念ながら) fstream::open() など、設計が不十分ないくつかの C++ API を使用するときだけです。

第三に、ストリーム操作が機能したかどうかをテストする標準的な方法は、操作自体をテストすることです。ストリームには void * への変換があります。つまり、次のように記述できます。

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

入力または出力のいずれであっても、コードは常にストリーム操作をテストする必要があります。

于 2010-04-09T08:42:46.287 に答える
4

クローズ後のチェック以外はすべて妥当なようです。そうは言っても、私は物事を少し違った方法で再構築し、例外をスローするか、を使用しますboolが、それは単に好みの問題です:

ブールセーバー::出力()
{
    std::fstream out(_filename.c_str(),std::ios::out);
    if ( ! out.is_open() ){
         LOG4CXX_ERROR(_logger,"\""<<ファイル名<<"\"") を開けませんでした。
         false を返します。
    }

    out << _savestr << std::endl;
    if ( out.bad() ){
         LOG4CXX_ERROR(_logger,"\""<<ファイル名<<"\""に保存できませんでした");
         out.close();
         false を返します。
    }

    out.close();
    true を返します。
}

save_str.c_str()C++ iostream (fstream、ofstream などを含む) はすべて std::string オブジェクトを出力できるため、を使用する必要がないことも指摘しておく必要があります。また、関数のスコープ内でファイル ストリーム オブジェクトを構築すると、スコープ外になると自動的に閉じられます。

于 2010-04-09T08:15:08.673 に答える
2

save_file_handleに関連付けられた (開いている) ファイルがまだないことを絶対に確信していますか? open()その場合、そのメソッドの呼び出しは失敗し、ios::failbitエラー フラグが発生します。また、そのように設定されている場合はすべての例外が発生します。

ファイルが開かれていない限り、メソッドは失敗しません。close()その場合、メソッドはios::failbitエラー フラグを立てます。とにかく、デストラクタはファイルを閉じる必要があり、save_file_handleコードのようにスタック変数の場合は自動的に閉じます。

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;
}

または、 を使用する場合は、エラー チェックをファイル保存ロジックから分離できます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;
}

呼び出しをsave_file_handle.exceptions(ios::failbit | ios::badbit)コンストラクターに移動することをお勧めします。次に、例外フラグをリセットするステートメントを取り除くことができます。

于 2010-04-09T08:41:33.017 に答える