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

当我在 Total Commander 和 Windows Explorer 中观察文件时,我发现文件大小保持不变。我可以进入文件所在的目录,然后从目录中退出,然后再次进入 - 文件大小是恒定的(在 Total Commander 和 Windows 资源管理器中),直到我手动刷新 Windows 资源管理器中的目录内容F5

当我在 Windows XP 中运行相同的程序时,Total Commander 和 Windows Explorer 不断显示文件大小正在增加。

我想知道是什么问题。是 NTFS 行为、软件设置还是其他?

先感谢您!

4

2 回答 2

3

这篇关于旧新事物的文章。基本上,它与效率有关。最新的文件元数据(例如它的大小)不与目录条目一起存储,而是与文件本身一起存储(这类似于某些 UNIX 文件系统的工作方式,并且与旧的 FAT 方法相反)。

但是,大小会定期传输到目录条目,以便您可以获得“最后一个已知”值。并且,在某个时间点(文件停止更改后),最后一个已知值变得准确。

从那篇文章:

在 NTFS 中,文件系统元数据不是目录条目的属性,而是文件的属性,其中一些元数据复制到目录条目中作为改进目录枚举性能的调整。FindFirstFile 之类的函数报告目录条目,并且通过放置 FAT 用户习惯“免费”获得的元数据,它们可以避免目录列表比 FAT 慢。目录枚举函数报告最后更新的元数据,如果目录条目是陈旧的,则该元数据可能与实际元数据不对应。

下一个问题是元数据复制在何处以及多久进行一次;换句话说,这些数据的陈旧程度如何?为了避免每次文件元数据更改时都必须更新可能无限数量的目录条目,NTFS 人员决定仅从文件执行复制到用于打开文件的目录条目。这意味着如果一个文件有一千个硬链接,文件大小的变化将反映在用于打开文件的目录条目中,但其他 999 个目录条目将包含陈旧数据。

从 Windows Vista 开始(及其对应的 Windows Server 版本,我不知道,但我相信你可以查找,“你”是指“雨红包”),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 回答