我希望能够使用C#获取其中一个本地目录的大小。我试图避免以下(伪代码),尽管在最坏的情况下我将不得不满足于此:
int GetSize(Directory)
{
int Size = 0;
foreach ( File in Directory )
{
FileInfo fInfo of File;
Size += fInfo.Size;
}
foreach ( SubDirectory in Directory )
{
Size += GetSize(SubDirectory);
}
return Size;
}
基本上,是否有可以在某处使用Walk()以便我可以浏览目录树?这将保存遍历每个子目录的递归。
答案 0 :(得分:32)
在.net 4.0中获取文件夹大小的一种非常简洁的方法如下。它仍然受到必须以递归方式遍历所有文件的限制,但它不会加载潜在的大量文件名,而且只有两行代码。
private static long GetDirectorySize(string folderPath)
{
DirectoryInfo di = new DirectoryInfo(folderPath);
return di.EnumerateFiles("*.*", SearchOption.AllDirectories).Sum(fi => fi.Length);
}
答案 1 :(得分:19)
如果您使用Directory.GetFiles
,您可以执行递归搜索(使用SearchOption.AllDirectories
),但无论如何这都有点不稳定(特别是如果您无法访问其中一个子目录) - 并且可能涉及一个巨大的单个阵列回来(警告klaxon ......)。
我会对递归方法感到满意,除非我能显示(通过分析)瓶颈;然后我可能会切换到(单级)Directory.GetFiles
,使用Queue<string>
来模拟递归。
请注意,.NET 4.0引入了一些基于枚举器的文件/目录列表方法,可以节省大数组。
答案 2 :(得分:6)
这是我的.NET 4.0方法
public static long GetFileSizeSumFromDirectory(string searchDirectory)
{
var files = Directory.EnumerateFiles(searchDirectory);
// get the sizeof all files in the current directory
var currentSize = (from file in files let fileInfo = new FileInfo(file) select fileInfo.Length).Sum();
var directories = Directory.EnumerateDirectories(searchDirectory);
// get the size of all files in all subdirectories
var subDirSize = (from directory in directories select GetFileSizeSumFromDirectory(directory)).Sum();
return currentSize + subDirSize;
}
甚至更好:
// get IEnumerable from all files in the current dir and all sub dirs
var files = Directory.EnumerateFiles(searchDirectory,"*",SearchOption.AllDirectories);
// get the size of all files
long sum = (from file in files let fileInfo = new FileInfo(file) select fileInfo .Length).Sum();
正如Gabriel指出,如果您在searchDirectory下有一个受限制的目录,那么这将失败!
答案 3 :(得分:4)
您可以隐藏扩展方法后面的递归(以避免Marc使用GetFiles()方法突出显示的问题):
public static IEnumerable<FileInfo> Walk(this DirectoryInfo directory)
{
foreach(FileInfo file in directory.GetFiles())
{
yield return file;
}
foreach(DirectoryInfo subDirectory in directory.GetDirectories()
{
foreach(FileInfo file in subDirectory.Walk())
{
yield return file;
}
}
}
(您可能希望为受保护的文件夹等添加一些异常处理。)
然后:
int totalSize = 0;
foreach(FileInfo file in directory.Walk())
{
totalSize += file.Length;
}
基本上是相同的代码,但也许有点整洁......
答案 4 :(得分:3)
首先,请原谅我可怜的英语; o) 我有一个问题带我到这个页面:枚举目录及其子目录的文件而不会阻止UnauthorizedAccessException,并且像.Net 4 DirectoryInfo.Enumerate ...的新方法一样,在结束之前得到第一个结果整个查询。
借助在网上找到的各种例子的帮助,我终于写了这个方法:
public static IEnumerable<FileInfo> EnumerateFiles_Recursive(this DirectoryInfo directory, string searchPattern, SearchOption searchOption, Func<DirectoryInfo, Exception, bool> handleExceptionAccess)
{
Queue<DirectoryInfo> subDirectories = new Queue<DirectoryInfo>();
IEnumerable<FileSystemInfo> entries = null;
// Try to get an enumerator on fileSystemInfos of directory
try
{
entries = directory.EnumerateFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly);
}
catch (Exception e)
{
// If there's a callback delegate and this delegate return true, we don't throw the exception
if (handleExceptionAccess == null || !handleExceptionAccess(directory, e))
throw;
// If the exception wasn't throw, we make entries reference an empty collection
entries = EmptyFileSystemInfos;
}
// Yield return file entries of the directory and enqueue the subdirectories
foreach (FileSystemInfo entrie in entries)
{
if (entrie is FileInfo)
yield return (FileInfo)entrie;
else if (entrie is DirectoryInfo)
subDirectories.Enqueue((DirectoryInfo)entrie);
}
// If recursive search, we make recursive call on the method to yield return entries of the subdirectories.
if (searchOption == SearchOption.AllDirectories)
{
DirectoryInfo subDir = null;
while (subDirectories.Count > 0)
{
subDir = subDirectories.Dequeue();
foreach (FileInfo file in subDir.EnumerateFiles_Recursive(searchPattern, searchOption, handleExceptionAccess))
{
yield return file;
}
}
}
else
subDirectories.Clear();
}
我使用Queue和递归方法来保持传统的顺序(目录的内容,然后是第一个子目录的内容和他自己的子目录,然后是第二个的内容......)。参数“handleExceptionAccess”只是在用目录抛出异常时的函数调用;该函数必须返回true以指示必须忽略该异常。
使用这种方法,你可以写:
DirectoryInfo dir = new DirectoryInfo("c:\\temp");
long size = dir.EnumerateFiles_Recursive("*", SearchOption.AllDirectories, (d, ex) => true).Sum(f => f.Length);
我们在这里:尝试枚举目录时的所有异常都将被忽略!
希望这个帮助
梅西
PS:因为我无法解释的原因,我的方法比框架4更快......PPS:您可以使用这些方法的源代码获取我的测试解决方案:此处TestDirEnumerate。我编写EnumerateFiles_Recursive,EnumerateFiles_NonRecursive(使用队列来避免递归)和EnumerateFiles_NonRecursive_TraditionalOrder(使用一堆队列来避免递归并保持传统顺序)。保持这3种方法没有兴趣,我写它们只是为了测试最好的方法。我想只保留最后一个。 我还为EnumerateFileSystemInfos和EnumerateDirectories编写了等效文件。
答案 5 :(得分:1)
看一下这篇文章:
http://social.msdn.microsoft.com/forums/en-US/vbgeneral/thread/eed54ebe-facd-4305-b64b-9dbdc65df04e
基本上没有干净的.NET方法,但有一种非常简单的COM方法,所以如果你对使用COM互操作并与Windows绑定感到满意,这可能对你有用。
答案 6 :(得分:1)
解决方案已经在https://stackoverflow.com/a/12665904/1498669
与所示的重复How do I Get Folder Size in C#?一样 - &gt;你也可以在c#
中做到这一点首先,将COM引用“Microsoft Scripting Runtime”添加到项目中并使用:
var fso = new Scripting.FileSystemObject();
var folder = fso.GetFolder(@"C:\Windows");
double sizeInBytes = folder.Size;
// cleanup COM
System.Runtime.InteropServices.Marshal.ReleaseComObject(folder);
System.Runtime.InteropServices.Marshal.ReleaseComObject(fso);
记得清理COM引用
答案 7 :(得分:0)
前段时间我一直在寻找类似于你所要求的功能,以及我在互联网和MSDN论坛上发现的功能,没有这样的功能。
考虑到包含所有文件和子文件夹,我发现获取文件夹大小的唯一递归方式。
答案 8 :(得分:-2)
你应该让自己轻松自如。制作方法并传递目录的位置。
private static long GetDirectorySize(string location) {
return new DirectoryInfo(location).GetFiles("*.*", SearchOption.AllDirectories).Sum(file => file.Length);
}
-G