我已经构建了一个递归函数来获取文件夹路径的目录大小。它有效,但随着我必须搜索的目录数量不断增加(以及每个相应文件夹中的文件数量),这是一种非常缓慢,低效的方法。
static string GetDirectorySize(string parentDir)
{
long totalFileSize = 0;
string[] dirFiles = Directory.GetFiles(parentDir, "*.*",
System.IO.SearchOption.AllDirectories);
foreach (string fileName in dirFiles)
{
// Use FileInfo to get length of each file.
FileInfo info = new FileInfo(fileName);
totalFileSize = totalFileSize + info.Length;
}
return String.Format(new FileSizeFormatProvider(), "{0:fs}", totalFileSize);
}
这是在所有子目录中搜索参数路径,因此dirFiles
数组变得非常大。有没有更好的方法来实现这一目标?我已经四处寻找,但还没有找到任何东西。
我想到的另一个想法是将结果放在缓存中,当再次调用该函数时,尝试查找差异并仅重新搜索已更改的文件夹。不确定这是不是一件好事......
答案 0 :(得分:25)
您首先扫描树以获取所有文件的列表。然后,您将重新打开每个文件以获得其大小。这相当于扫描两次。
我建议您使用DirectoryInfo.GetFiles
直接递送FileInfo
个对象。这些物体预先填充了它们的长度。
在 .NET 4 中,您还可以使用EnumerateFiles
方法,该方法会为您提供一个懒惰的IEnumable
。
答案 1 :(得分:12)
尝试
DirectoryInfo DirInfo = new DirectoryInfo(@"C:\DataLoad\");
Stopwatch sw = new Stopwatch();
try
{
sw.Start();
Int64 ttl = 0;
Int32 fileCount = 0;
foreach (FileInfo fi in DirInfo.EnumerateFiles("*", SearchOption.AllDirectories))
{
ttl += fi.Length;
fileCount++;
}
sw.Stop();
Debug.WriteLine(sw.ElapsedMilliseconds.ToString() + " " + fileCount.ToString());
}
catch (Exception Ex)
{
Debug.WriteLine(Ex.ToString());
}
在台式机NON-RAID P4上,这在70秒内完成了70万次。 所以像每秒10,000。在服务器类机器上应该容易获得100,000+ /秒。
正如usr(+1)所说,EnumerateFile预先填充了长度。
答案 2 :(得分:11)
这更加神秘,但10k执行需要大约2秒钟。
public static long GetDirectorySize(string parentDirectory)
{
return new DirectoryInfo(parentDirectory).GetFiles("*.*", SearchOption.AllDirectories).Sum(file => file.Length);
}
答案 3 :(得分:4)
您可以使用EnumerateFiles()
代替GetFiles()
开始加快您的功能。至少你不会在内存中加载完整列表。
如果还不够,你应该使用线程使你的函数更多复杂(每个目录一个线程太多,但没有一般规则)。
您可以使用固定数量的线程从队列中查看目录,每个线程计算目录的大小并添加到总计。类似的东西:
您可以改进跨越所有线程搜索目录的算法(例如,当线程解析目录时,它会将文件夹添加到队列中)。如果您觉得它太慢,可以使它变得更复杂(Microsoft已将此任务用作 new Task Parallel Library的示例。)
答案 4 :(得分:-1)
perl -e 'print pack("H*","d83ddd0e")' | iconv -f UTF-16 -t UTF-32 | hexdump -C