LoginSignup
1
0

More than 3 years have passed since last update.

ofstreamで可変長かつ1行だけのテキストファイルを出来るだけ瞬時に更新する方法

Last updated at Posted at 2019-11-07

概要

可変長かつ1行しかないCSVテキストファイルを、ほぼリアルタイムに更新したい。
close() → open(path) すれば中身を消せるが、中身が消える瞬間がある。
というのを、無理矢理マシにしたメモ。

方法

一時ファイルに書き込み、それをリネーム&上書きしました。
これでも、一瞬OSがファイルをロックしてしまいますが、中身が消えてるよりいいでしょう。
(ちなみに、固定長であれば、オープンしたままファイル先頭に seekp() するだけでいいいはず。)

環境は Visual Studio 2017のVC++(C++)です。

sample.cpp
#include <fstream>
#include <string>
#include <Windows.h>
using namespace std;

int main()
{
    ofstream ofs;
    string tmp_path = "./hoge_tmp";
    string out_path = "./hoge.csv";
    ofs.open(tmp_path);
    if (!ofs) {
        return 1;
    }

    int i = 0;
    while (1) {
        string str = to_string(i) + "," + to_string(i + 1);
        ofs << str << endl;
        ofs.close();
        BOOL ret;
        ret = MoveFileEx(tmp_path.c_str(), out_path.c_str(), MOVEFILE_REPLACE_EXISTING);
        // MoveFileEx()は以下でも可。以下の方がアトミックである信用度が高いが、
        // dst,src双方にファイルが無いと、ファイルが見つからないエラーとなる。
        // また、MoveFileEx()と、dst,srcが逆な事にも注意。
        // 実験した結果、ReplaceFile() は一瞬dst側を削除している事が判明。
        // 詳細は本ページのコメント参照。
        // ret = ReplaceFile(out_path.c_str(), tmp_path.c_str(), NULL, 0, NULL, NULL);
        if (ret == 0) {
            return 1;
        }
        ofs.open(tmp_path);
        if (!ofs) {
            return 1;
        }
        i++;
        Sleep(0); // ほぼウェイト無し無限ループ
    }
    return 0;
}

 
ファイルの現在状況は、コマンドプロンプトから以下のコマンドで確認できます。

cmd
type hoge.csv

コマンドプロンプトは、「↑」→「Enter」で前回を同じコマンドを実行できるので、「↑」→「Enter」→「↑」→「Enter」→ .. と繰り返せば、連続して開いてみることが出来ます。
close() → open() の場合は、連打するとよく空データが見えていましたが、本ページのコードにすると、時折アクセス拒否されるものの、空データが見えることは無くなりました。

※ 2019/11/08-1 MoveFileEx()の戻値チェック抜けていたので追記しました。
※ 2019/11/08-2 最後に補足つけたしました。
※ 2019/11/08-3 コード中にReplaceFile()についてコメント記載しました。コメント頂いた方ありがとうございました。
※ 2019/11/08-4 ReplaceFile()の挙動実験結果をコメントに追記しました。

1
0
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0