【问题标题】:File size doesn't change on Windows Server 2008Windows Server 2008 上的文件大小不会改变
【发布时间】:2012-04-04 08:18:22
【问题描述】:

与 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 资源管理器中),直到我通过 F5 在 Windows 资源管理器中手动刷新目录内容

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

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

提前感谢您!

【问题讨论】:

  • 无法确定,但很可能是某些缓存机制造成的。

标签: .net windows file ntfs


【解决方案1】:

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

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

来自那篇文章:

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

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

从 Windows Vista 开始(及其对应的 Windows Server 版本,我不知道,但我相信你可以查找,“你”是指“雨红包”),NTFS 文件系统执行此礼遇当文件对象的最后一个句柄关闭时进行复制。早期版本的 NTFS 会在缓存刷新时文件打开时复制数据,这意味着它会根据不可预知的时间表经常发生。此更改的结果是目录条目现在更新频率降低,因此最后更新的文件大小比以前更过时。

【讨论】:

    【解决方案2】:

    您可以使用 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;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-01
      • 2018-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多