11

別のプロセス (変更できない) によって継続的に書き込まれるバッファー ファイルからバイナリ データを読み込もうとしています。ファイルを開くために次のコードを使用しています。

fileH = CreateFileA((LPCSTR)filename,
                    GENERIC_READ,
                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                    NULL,
                    OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL, NULL);

そして、エラーなしで正しく開きます。ただし、ファイルからデータを読み取ると、データが失われるため、他のプロセスがファイルに書き込むのをブロックしているようです。

バッファは循環的です。つまり、ファイル サイズは固定されており、新しいデータは常にバッファ内の古いデータに上書きされます。

編集: 時には最も些細な解決策が機能します...

ソフトウェア会社に連絡してバグについて伝えたところ、1 日以内に修正された新しいバージョンが投稿されました。申し訳ありませんが、これは誰にとってもうまくいくわけではありません。

4

2 に答える 2

8

書き込みプロセスがファイルをどのように開いているかを知らずに、オプションが何であるかを言うのは困難です。明らかに、排他的アクセスのためにファイルを開いて開いたままにしているわけではありません。そうしないと、まったく読めません。

あなたが説明する動作は、書き込みプロセスが排他的アクセスのためにファイルを開き、それに書き込み、次にファイルを閉じることを示しています。その場合、プログラムでファイルを開いて開いたままにすることはできません。これにより、書き込みを試みるたびに書き込みプロセスが失敗します。

執筆プロセスを変更できない場合、選択肢は限られ、あまり魅力的ではありません。ほとんどの場合、プログラムでファイルを開き、小さなチャンクを読み取り、ファイルを閉じてから、再度読み取る前に少し待つ必要があります。それでも、書き込みプロセスが書き込みを試みたときにファイルが開かれないという保証はありません。これは、あなたがすでに発見していると思います。

ファイルを開くことができないときに書き込みプロセスがデータを失うのか、それともデータをバッファリングして、次に実際にファイルを開くことができるときに書き込むのかを知っていますか? その場合は、ファイルを少しずつステップ実行するという私の提案が機能する可能性があります。そうしないと、データが失われます。

私が知っているオープン モードはありません。これは、「読み取りのためにファイルを開きますが、誰かが排他的アクセスを必要とする場合は、それを許可します」に相当します。

もう 1 つの可能性は、読み取りたいときにいつでもプログラムでファイルの名前を変更し、読み取り後に名前を変更したファイルを削除することです。もちろん、これは、書き込みプロセスが必要に応じて新しいファイルを作成することを前提としています。それでも、名前の変更中に書き込みプロセスが書き込みを試みると、問題が発生する可能性があります。それが問題になるとは思いませんが (ファイル システムに関する限り、名前の変更はアトミックである可能性があります)、調査する必要があります。

于 2013-03-13T14:59:32.630 に答える
5

優れたFar Managerのソース コードを参照することをお勧めします。その内部ビューアは、数ギガバイトのファイルを簡単に処理でき、書き込み中のファイルを問題なく表示し、変更されたファイルの内容をほぼリアルタイムで更新できます。表示されているファイルのブロックの問題に気付いたことはありません。

質問に関連するソース コードは、viewer.cppファイルにあるようです。

興味深い点の 1 つは、以下を使用しないGENERIC_READことです。

ViewFile.Open(strFileName, FILE_READ_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, nullptr, OPEN_EXISTING);

ここではドロップSYNCHRONIZEが重要かもしれないと思います。

ファイル変更の検出はViewer::ProcessKey、次のKEY_IDLE場合です。

// Smart file change check -- thanks Dzirt2005
//
bool changed = (
    ViewFindData.ftLastWriteTime.dwLowDateTime!=NewViewFindData.ftLastWriteTime.dwLowDateTime ||
    ViewFindData.ftLastWriteTime.dwHighDateTime!=NewViewFindData.ftLastWriteTime.dwHighDateTime ||
    ViewFindData.nFileSize != NewViewFindData.nFileSize
);
if ( changed )
    ViewFindData = NewViewFindData;
else {
    if ( !ViewFile.GetSize(NewViewFindData.nFileSize) || FileSize == static_cast<__int64>(NewViewFindData.nFileSize) )
        return TRUE;
    changed = FileSize > static_cast<__int64>(NewViewFindData.nFileSize); // true if file shrank
}

キャッシュされたファイルの読み取りは、cache.cppに実装されています。しかし、本当に驚くべきことは何もなく、一部のSeek()and Read()(最終的SetFilePointerExand のReadFileAPI 呼び出しが発生する) だけです。OVERLAPPED は使用されません。

于 2013-03-13T14:10:33.510 に答える