現在のファイルの長さを取得する / FileInfo.Length のキャッシュと古い情報 質問する

現在のファイルの長さを取得する / FileInfo.Length のキャッシュと古い情報 質問する

ファイルのフォルダーとそのファイルの長さを追跡していますが、これらのファイルの少なくとも 1 つにはまだ書き込みが行われています。

他の目的で使用する各ファイルの長さの記録を継続的に更新しておく必要があります。

このUpdateメソッドは 15 秒ごとに呼び出され、ファイルの長さが前回の更新で決定された長さと異なる場合にファイルのプロパティを更新します。

更新メソッドは次のようになります。

var directoryInfo = new DirectoryInfo(archiveFolder);
var archiveFiles = directoryInfo.GetFiles()
                                .OrderByDescending(f=>f.CreationTimeUtc); 
foreach (FileInfo fi in archiveFiles)
{
    //check if file existed in previous update already
    var origFileProps = cachedFiles.GetFileByName(fi.FullName);
    if (origFileProps != null && fi.Length == origFileProps.EndOffset)
    {
        //file length is unchanged
    }
    else
    {
        //Update the properties of this file
        //set EndOffset of the file to current file length
    }
}

私は、DirectoryInfo.GetFiles()多くのプロパティが事前に入力されていますFileInfoLengthキャッシュが行われない限り、これは問題ありません。更新(キャッシュされた情報は 15 秒以内である必要があります)。

私は、各DirectoryInfo.GetFiles()通話が新しいそのセットはすべて、 / Win32 APIFileInfosを使用して最新の情報ですぐに設定されます。しかし、そうではないようです。FindFirstFileFindNextFile

非常に稀ですが、最終的には、書き込み先のファイルのファイル長が一度に 5 分、10 分、または 20 分間更新されない状況に遭遇します (テストは Windows 2008 Server x64 で行われます)。

fi.Refresh()現在の回避策は、各ファイル情報の更新を強制するために を呼び出すことです。これは、内部的にはGetFileAttributesEx、ファイル情報の更新を Win32 API 呼び出しに委任しているようです。

手動で強制的に更新するコストは許容できるが、私はむしろ理解したいなぜそもそも古い情報を取得しています。FileInfo情報はいつ生成され、 の呼び出しとどのように関連しているのでしょうかDirectoryInfo.GetFiles()。その下には、私が完全に理解していないファイル I/O キャッシュ レイヤーがあるのでしょうか。

ベストアンサー1

Raymond Chen 氏は、まさにこの問題について非常に詳細なブログ記事を書いています。

まだ書き込み中のファイルのファイル サイズが誤って報告されるのはなぜですか?

NTFSでは、ファイルシステムのメタデータは、ディレクトリエントリではなくファイルのプロパティであり、ディレクトリ列挙のパフォーマンスを向上させるために、メタデータの一部がディレクトリエントリに複製されます。FindFirstFile などの関数はディレクトリ エントリを報告し、FAT ユーザーが「無料で」取得することに慣れていたメタデータを配置することで、ディレクトリ リストの表示が FAT よりも遅くなるのを回避できます。ディレクトリ列挙関数は最後に更新されたメタデータを報告しますが、ディレクトリ エントリが古い場合は実際のメタデータと一致しない可能性があります。

基本的には、パフォーマンスの問題です。ディレクトリ情報DirectoryInfo.GetFiles()とその下のFindFirstFile/ FindNextFileWin32 API から収集されたディレクトリ情報は、パフォーマンス上の理由からキャッシュされ、ディレクトリ情報を取得する際に、古い FAT よりも NTFS で優れたパフォーマンスが保証されます。正確なファイル サイズ情報は、Get­File­Size()ファイルを直接呼び出す (.NET では、 を呼び出すRefresh()か、ファイル名から直接FileInfoを取得するFileInfo) か、ファイル ストリームを開いて閉じる (これにより、更新されたファイル情報がディレクトリ メタデータ キャッシュに伝播される) ことによってのみ取得できます。後者の場合、書き込みプロセスがファイルを閉じるとファイル サイズがすぐに更新される理由が説明されます。

これは、Windows 2003 Server では問題が発生しなかったように見えることも説明しています。当時は、ファイル情報はより頻繁に、またはキャッシュがフラッシュされるたびに複製されていましたが、Windows 2008 Server ではそうではありません。

どのくらいの頻度で行われるかという質問に対する答えは、もう少し複雑です。Windows Vista (および対応する Windows Server バージョンについては知りませんが、調べることはできると思います。ここでの「あなた」とは、「Yuhong Bao」のことです) 以降では、ファイル オブジェクトへの最後のハンドルが閉じられると、NTFS ファイル システムはこの礼儀正しいレプリケーションを実行します。以前のバージョンの NTFS では、キャッシュがフラッシュされるたびにファイルが開いている間にデータが複製されていました。つまり、予測できないスケジュールに従って、時々複製が行われていました。この変更の結果、ディレクトリ エントリが更新される頻度が低くなり、最後に更新されたファイルのサイズが以前よりも古くなっています。

記事全文を読むと非常に有益な情報が得られるので、お勧めです。

おすすめ記事