如何在C#中获得目录大小(目录中的文件)?
我希望能够使用C#获得一个本地目录的大小。我试图避免以下情况(伪代码),尽管在最坏的情况下,我必须满足于此:如何在C#中获得目录大小(目录中的文件)?,c#,asp.net,winforms,.net,C#,Asp.net,Winforms,.net,我希望能够使用C#获得一个本地目录的大小。我试图避免以下情况(伪代码),尽管在最坏的情况下,我必须满足于此: int GetSize(Directory) { int Size = 0; foreach ( File in Directory ) { FileInfo fInfo of File; Size += fInfo.Size; } fore
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()可以让我遍历目录树?这将节省遍历每个子目录的递归。我不久前一直在寻找一个类似您要求的函数,从我在Internet和MSDN论坛上找到的内容来看,没有这样的函数
private static long GetDirectorySize(string location) {
return new DirectoryInfo(location).GetFiles("*.*", SearchOption.AllDirectories).Sum(file => file.Length);
}
考虑到包含的所有文件和子文件夹,递归方法是我发现的唯一一种获取文件夹大小的方法。如果使用
目录。GetFiles
可以进行递归搜索(使用SearchOption.AllDirectories
),但这还是有点古怪(特别是如果您没有访问其中一个子目录的权限)-并且可能需要一个巨大的数组返回(警告klaxon…)
我很乐意使用递归方法,除非我可以(通过分析)显示瓶颈;然后我可能会切换到(单级)Directory.GetFiles
,使用队列来模拟递归
请注意,.NET 4.0引入了一些基于枚举数的文件/目录列表方法,这些方法保存在大数组中。您可以将递归隐藏在扩展方法后面(以避免Marc使用GetFiles()方法突出显示的问题):
公共静态类UserExtension
{
公共静态IEnumerable Walk(此DirectoryInfo目录)
{
foreach(目录.GetFiles()中的FileInfo文件)
{
生成返回文件;
}
foreach(directory.GetDirectories()中的DirectoryInfo子目录)
{
foreach(子目录.Walk()中的FileInfo文件)
{
生成返回文件;
}
}
}
}
(对于受保护的文件夹等,您可能希望为此添加一些异常处理。)
然后:
使用静态用户扩展;
长总尺寸=0升;
var startFolder=新目录信息(“”);
//迭代
foreach(startFolder.Walk()中的FileInfo文件)
{
totalSize+=文件长度;
}
//林克
totalSize=di.Walk().Sum(s=>s.Length);
基本上相同的代码,但可能有点整洁…看看这篇文章:
基本上没有干净的.NET方法,但有一种非常简单的COM方法,因此如果您对使用COM互操作和绑定到Windows感到满意,这可能对您有用。这里是我的.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下有一个受限目录,则此操作将失败!首先,请原谅我的蹩脚英语;o)
我遇到了一个问题,这个问题把我带到了这个页面:枚举目录及其子目录的文件,而不阻塞未经授权的访问异常,并且,像.Net 4 DirectoryInfo.enumerate…的新方法一样,在整个查询结束之前获得第一个结果
借助于web上随处可见的各种示例,我最终编写了以下方法:
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();
}
现在我们看到了:当尝试枚举目录时,所有异常都将被忽略
希望这有帮助
莱昂内尔
PS:由于一个我无法解释的原因,我的方法比框架4更快
PPS:您可以从这些方法的源代码中获得我的测试解决方案:这里。我编写EnumerateFiles\u Recursive、EnumerateFiles\u NonRecursive(使用队列避免递归)和EnumerateFiles\u NonRecursive\u TraditionalOrder(使用队列堆栈避免递归并保持传统顺序)。保持这3种方法没有兴趣,我写它们只是为了测试最好的方法。我想只保留最后一个。
我还为EnumerateFileSystemFos和EnumerateDirectory编写了等效程序。下面是在.NET4.0中获取文件夹大小的一种非常简洁的方法。它仍然受到必须递归遍历所有文件的限制,但它不会加载潜在的巨大文件名数组,而且只需两行代码。确保使用名称空间System.IO
和System.Linq
private static long GetDirectorySize(string folderPath)
{
DirectoryInfo di = new DirectoryInfo(folderPath);
return di.EnumerateFiles("*.*", SearchOption.AllDirectories).Sum(fi => fi.Length);
}
你应该放松自己。创建一个方法并遍历目录的位置
private static long GetDirectorySize(string location) {
return new DirectoryInfo(location).GetFiles("*.*", SearchOption.AllDirectories).Sum(file => file.Length);
}
-解决方案已经在这里了
如图所示->您也可以在c中执行此操作#
首先,将COM引用“Microsoft脚本运行时”添加到项目中,并使用:
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引用最后一行代码中的小错误,应该是://get the size of all files long sum=(从files in files let fileInfo=new fileInfo(file)选择fileInfo.Length).sum();如果您在searchDirectory下有一个受限目录,它将失败!在未来版本的框架中看到这一解决方案:感谢您的评论Gabriel。我已经修复了输入错误,并包含了可能的失败警告。我在这个版本中犯了一个错误,因为我使用searchPattern搜索目录。因此,如果一个子目录与searchPattern不匹配,我不会对其进行探索…[br]我编写了新版本以更正此问题:但是,我必须对目录执行两个请求:一个使用searchPattern,另一个不使用searchPattern==>性能不如以前。因此,我添加了一个不使用searchPattern的版本,速度更快。看看我的测试解决方案:也许我遗漏了一些东西,但是使用这种方法,您仍然会得到不完整的列表,对吗?如果我被授权查看文件夹A和C而不是B,并且Enumerate
检查A,然后检查B,然后检查C,它将停止使用B,并且无法计算C。我建议您使用*而不是*因为文件名不需要。我理解你的推理,但我认为这是不必要的,因为Windows操作系统将匹配**针对文件/文件夹名称的模式,无论它们是否包含“.”。我认为这没什么区别,但我很想知道我是否错了。当然,如果是Mono在不同的平台上运行
private static long GetDirectorySize(string location) {
return new DirectoryInfo(location).GetFiles("*.*", SearchOption.AllDirectories).Sum(file => file.Length);
}
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);