0

Windows XPと比較して、Windows Server 2008でファイルに継続的に書き込むと、奇妙な動作に気づきました。

私はいくつかのスレッドからそのようなものを実行します:

using (var fi = File.Open(...))
{
   using (var fw = new StreamWriter(fi)) 
   {
       while program-is-running 
       {
          fw.WriteLine(some-data);
          fw.Flush();
        }
    }
}            

TotalCommanderとWindowsExplorerでファイルを観察すると、ファイルサイズが一定に保たれていることがわかります。ファイルが配置されているディレクトリに移動し、ディレクトリから移動して、もう一度移動できます-Windowsエクスプローラーでディレクトリコンテンツを手動で更新するまで、ファイルサイズは一定です(TotalCommanderおよびWindowsExplorerで)。F5

Windows XPで同じプログラムを実行すると、TotalCommanderとWindowsExplorerは、ファイルサイズが増加していることを継続的に示します。

何が問題なのかしら。それはNTFSの動作、ソフトウェア設定、または他の何かですか?

前もって感謝します!

4

2 に答える 2

3

The Old New Thingに関するこの記事を参照してください。基本的に、それは効率と関係があります。最新のファイル メタデータ (サイズなど) は、ディレクトリ エントリではなく、ファイル自体に格納されます (これは、一部の UNIX ファイル システムの動作に似ており、古い FAT 方式とは対照的です)。

ただし、サイズは定期的にディレクトリ エントリに転送されるため、「最後に確認された」値を取得できます。そして、ある時点 (ファイルが変更を停止した後) で、最後の既知の値が正確になります。

その記事から:

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

次の質問は、このメタデータの複製がどこで、どのくらいの頻度で行われるかです。言い換えれば、このデータはどの程度古いものを取得できるのでしょうか? ファイルのメタデータが変更されるたびに無制限の数のディレクトリ エントリを更新する必要がないように、NTFS 関係者は、ファイルから、ファイルを開くために使用されたディレクトリ エントリへのレプリケーションのみを実行することにしました。つまり、ファイルに 1000 個のハード リンクがある場合、ファイル サイズの変更は、ファイルを開くために使用されたディレクトリ エントリに反映されますが、他の 999 個のディレクトリ エントリには古いデータが含まれます。

Windows Vista (およびそれに対応する Windows Server のバージョンはわかりませんが、調べてみるとわかると思います。「あなた」とは「Yuhong Bao」を意味します) 以降、NTFS ファイル システムは、ファイル オブジェクトへの最後のハンドルが閉じられます。以前のバージョンの NTFS では、キャッシュがフラッシュされるたびにファイルが開いている間にデータがレプリケートされました。つまり、予測できないスケジュールに従って頻繁に発生していました。この変更の結果、ディレクトリ エントリが更新される頻度が減ったため、最後に更新されたファイル サイズは以前よりも古くなっています。

于 2012-04-04T08:23:29.587 に答える
0

WMI を使用して、開いているファイルの正しいファイル サイズを取得できます。

Using System.Management;

internal static ManagementObject GetFileManagementObject(string pfilepath)
        {
            string filepath = pfilepath.Replace("\\", "\\\\");
            string scope = @"\\" + System.Environment.MachineName + @"\root\CIMV2";
            string query = string.Format("Select FileSize from CIM_DataFile WHERE Name     = '{0}'", filepath);
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
            ManagementObjectCollection collection = searcher.Get();
        foreach (ManagementObject mobj in searcher.Get())
        {
            return mobj;
        }


        return (null);
    }

private long GetFileSizeOpenFile(string path)
    {
        long fsize = -1;
        try
        {
            ManagementObject mObj = Statics.GetFileManagementObject(path);
            string sSize = mObj.Properties["FileSize"].Value.ToString();
            long.TryParse(sSize, out fsize);
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
        return fsize;
    }
于 2012-06-14T18:38:11.447 に答える