目录文件大小计算 – 如何使其更快?

使用C#,我find一个目录的总大小。 逻辑是这样的:获取文件夹内的文件。 总计总大小。 查找是否有子目录。 然后做一个recursionsearch。

我尝试了另一种方式来做到这一点:使用FSO( obj.GetFolder(path).Size )。 这两种方法在时间上没有太大的区别。

现在的问题是,我有一个特定的文件夹中的数以万计的文件,并采取像至less2分钟,以find文件夹的大小。 另外,如果我再次运行程序,它会很快(5秒)发生。 我认为窗户caching的文件大小。

有什么办法可以减less我第一次运行程序所花费的时间?

如果弄了一会儿,尝试并行化,而且令人惊讶的是 – 它在我的机器上加速(在一个quadcore上达到3次),不知道它是否在所有情况下都是有效的,但是试一试。 ..

.NET4.0代码(或与TaskParallelLibrary一起使用3.5)

  private static long DirSize(string sourceDir, bool recurse) { long size = 0; string[] fileEntries = Directory.GetFiles(sourceDir); foreach (string fileName in fileEntries) { Interlocked.Add(ref size, (new FileInfo(fileName)).Length); } if (recurse) { string[] subdirEntries = Directory.GetDirectories(sourceDir); Parallel.For<long>(0, subdirEntries.Length, () => 0, (i, loop, subtotal) => { if ((File.GetAttributes(subdirEntries[i]) & FileAttributes.ReparsePoint) != FileAttributes.ReparsePoint) { subtotal += DirSize(subdirEntries[i], true); return subtotal; } return 0; }, (x) => Interlocked.Add(ref size, x) ); } return size; } 

硬盘是一个有趣的野兽 – 顺序访问(例如读取一个大的连续文件)是超级灵活的,数字80兆字节/秒。 但随机访问非常缓慢。 这就是你碰到的东西 – 递归到文件夹不会读取太多(在数量上)的数据,但将需要许多随机读取。 你之所以能看到第二个答案,是因为MFT仍然在RAM中(你对缓存思想是正确的)

我见过的最好的机制是自己扫描MFT。 这个想法是你阅读和解析MFT在一个线性的通行证,建立你所需要的信息,你去。 最终的结果将是非常接近15秒的HD。

一些很好的阅读:NTFSInfo.exe – http://technet.microsoft.com/en-us/sysinternals/bb897424.aspx Windows内部 – http://www.amazon.com/Windows%C2%AE-Internals-Including- Windows的PRO-开发商/ DP / 0735625301 / REF = sr_1_1?IE = UTF8&S =书籍和QID = 1277085832&SR = 8-1

FWIW:这个方法非常复杂,因为在Windows(或者我知道的任何操作系统)中确实没有这么做的方法 – 问题在于确定需要哪些文件夹/文件需要很多的工作在磁盘上移动。 微软为你描述的问题建立一个通用的解决方案是非常困难的。

最简洁的答案是不。 Windows可以使目录大小计算更快的方法是更新每个文件写入时的目录大小和所有父目录大小。 但是,这会使文件写入较慢的操作。 由于文件写入比读取目录大小更为常见,这是一个合理的折衷。

我不知道什么确切的问题正在解决,但如果它是文件系统监视它可能值得检查: http : //msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx

我不认为它会改变很多,但如果你使用API​​函数FindFirstFileNextFile来做,它可能会更快一些。

但是我不认为有什么快速的方法可以做到这一点。 为了比较的目的,你可以尝试做dir /a /x /s > dirlist.txt并在Windows资源管理器中列出目录来查看它们有多快,但我认为它们将类似于FindFirstFile

PInvoke有一个如何使用API​​的示例。

在使用数万个文件扫描文件夹时,性能会受到任何方法的影响。

  • 使用Windows API FindFirstFile …和FindNextFile …函数提供了最快的访问。

  • 由于编组开销,即使您使用Windows API函数,性能也不会增加。 这个框架已经包装了这些API函数,所以你自己做这个没有意义。

  • 如何处理任何文件访问方法的结果决定了应用程序的性能。 例如,即使使用Windows API函数,更新列表框也会影响性能。

  • 您无法将执行速度与Windows资源管理器进行比较。 从我的实验中,我相信Windows Explorer在很多情况下直接从文件分配表中读取。

  • 我知道最快的访问文件系统是DIR命令。 您无法将性能与此命令进行比较。 它绝对直接从文件分配表(可能使用BIOS)读取。

  • 是的,操作系统缓存文件访问。

建议

  • 我不知道BackupRead会帮助你的情况吗?

  • 如果你掏出DIR并捕获然后解析它的输出呢? (你不是真的解析,因为每个DIR行是固定宽度,所以这只是一个调用子字符串的问题。)

  • 如果你在后台线程上执行DIR /B > NULL然后运行你的程序呢? 在DIR运行时,您将从缓存的文件访问中受益。

数以万计的文件,你不会赢得与正面攻击。 您需要尝试在解决方案方面更有创意。 有了这么多的文件,你甚至可能会发现,在你计算大小的时候,文件已经改变,你的数据已经是错误的。

所以,你需要把负载移到别的地方。 对我来说,答案将是使用System.IO.FileSystemWatcher并编写一些代码来监视目录并更新索引。

编写一个可以配置为监视一组目录并将结果写入共享输出文件的Windows服务应该只需要很短的时间。 您可以让服务在启动时重新计算文件大小,但是只要System.IO.FileSystemWatcher触发Create / Delete / Changed事件,就可以监视更改。 监控目录的好处是,你只对小的变化感兴趣,这意味着你的数字有更高的正确率(记住所有的数据是陈旧的!)

然后,唯一要注意的是你将有多个资源都试图访问生成的输出文件。 所以只要确保你考虑到这一点。

我放弃了.NET实现(出于性能原因),并使用Native函数GetFileAttributesEx(…)

尝试这个:

 [StructLayout(LayoutKind.Sequential)] public struct WIN32_FILE_ATTRIBUTE_DATA { public uint fileAttributes; public System.Runtime.InteropServices.ComTypes.FILETIME creationTime; public System.Runtime.InteropServices.ComTypes.FILETIME lastAccessTime; public System.Runtime.InteropServices.ComTypes.FILETIME lastWriteTime; public uint fileSizeHigh; public uint fileSizeLow; } public enum GET_FILEEX_INFO_LEVELS { GetFileExInfoStandard, GetFileExMaxInfoLevel } public class NativeMethods { [DllImport("KERNEL32.dll", CharSet = CharSet.Auto)] public static extern bool GetFileAttributesEx(string path, GET_FILEEX_INFO_LEVELS level, out WIN32_FILE_ATTRIBUTE_DATA data); } 

现在只需执行以下操作:

 WIN32_FILE_ATTRIBUTE_DATA data; if(NativeMethods.GetFileAttributesEx("[your path]", GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, out data)) { long size = (data.fileSizeHigh << 32) & data.fileSizeLow; }