C# 在 .NET 中计算目录大小的最佳方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/468119/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the best way to calculate the size of a directory in .NET?
提问by Steve Wranovsky
I've written the following routine to manually traverse through a directory and calculate its size in C#/.NET:
我编写了以下例程来手动遍历目录并在 C#/.NET 中计算其大小:
protected static float CalculateFolderSize(string folder)
{
float folderSize = 0.0f;
try
{
//Checks if the path is valid or not
if (!Directory.Exists(folder))
return folderSize;
else
{
try
{
foreach (string file in Directory.GetFiles(folder))
{
if (File.Exists(file))
{
FileInfo finfo = new FileInfo(file);
folderSize += finfo.Length;
}
}
foreach (string dir in Directory.GetDirectories(folder))
folderSize += CalculateFolderSize(dir);
}
catch (NotSupportedException e)
{
Console.WriteLine("Unable to calculate folder size: {0}", e.Message);
}
}
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("Unable to calculate folder size: {0}", e.Message);
}
return folderSize;
}
I have an application which is running this routine repeatedly for a large number of folders. I'm wondering if there's a more efficient way to calculate the size of a folder with .NET? I didn't see anything specific in the framework. Should I be using P/Invoke and a Win32 API? What's the most efficient way of calculating the size of a folder in .NET?
我有一个应用程序,它为大量文件夹重复运行此例程。我想知道是否有更有效的方法来计算 .NET 文件夹的大小?我没有看到框架中的任何特定内容。我应该使用 P/Invoke 和 Win32 API 吗?在 .NET 中计算文件夹大小的最有效方法是什么?
采纳答案by Mike Thompson
I do not believe there is a Win32 API to calculate the space consumed by a directory, although I stand to be corrected on this. If there were then I would assume Explorer would use it. If you get the Properties of a large directory in Explorer, the time it takes to give you the folder size is proportional to the number of files/sub-directories it contains.
我不相信有一个 Win32 API 来计算目录消耗的空间,尽管我会对此进行纠正。如果有的话,我会假设 Explorer 会使用它。如果您在资源管理器中获得大目录的属性,则为您提供文件夹大小所需的时间与它包含的文件/子目录的数量成正比。
Your routine seems fairly neat & simple. Bear in mind that you are calculating the sum of the file lengths, not the actual space consumed on the disk. Space consumed by wasted space at the end of clusters, file streams etc, are being ignored.
你的日常工作看起来相当整洁和简单。请记住,您计算的是文件长度的总和,而不是磁盘上消耗的实际空间。集群末尾浪费的空间、文件流等所消耗的空间被忽略。
回答by hao
No, this looks like the recommended wayto calculate directory size, the relevent method included below:
不,这看起来像是计算目录大小的推荐方法,相关方法包括如下:
public static long DirSize(DirectoryInfo d)
{
long size = 0;
// Add file sizes.
FileInfo[] fis = d.GetFiles();
foreach (FileInfo fi in fis)
{
size += fi.Length;
}
// Add subdirectory sizes.
DirectoryInfo[] dis = d.GetDirectories();
foreach (DirectoryInfo di in dis)
{
size += DirSize(di);
}
return size;
}
You would call with the root as:
你会用根调用:
Console.WriteLine("The size is {0} bytes.", DirSize(new DirectoryInfo(targetFolder));
...where targetFolder
is the folder-size to calculate.
...targetFolder
要计算的文件夹大小在哪里。
回答by Samuel
This it the best way to calculate the size of a directory. Only other way would still use recursion but be a bit easier to use and isn't as flexible.
这是计算目录大小的最佳方法。只有其他方式仍然会使用递归,但更容易使用并且不那么灵活。
float folderSize = 0.0f;
FileInfo[] files = Directory.GetFiles(folder, "*", SearchOption.AllDirectories);
foreach(FileInfo file in files) folderSize += file.Length;
回答by Jonathan C Dickinson
As far as the best algorithm goes you probably have it right. I would recommend that you unravel the recursive function and use a stack of your own (remember a stack overflow is the end of the world in a .Net 2.0+ app, the exception can not be caught IIRC).
就最佳算法而言,您可能是对的。我建议您解开递归函数并使用自己的堆栈(请记住,堆栈溢出是 .Net 2.0+ 应用程序中的世界末日,IIRC 无法捕获异常)。
The most important thing is that if you are using it in any form of a UI put it on a worker thread that signals the UI thread with updates.
最重要的是,如果您在任何形式的 UI 中使用它,请将它放在一个工作线程上,该线程向 UI 线程发送更新信号。
回答by Rodolfo G.
I've been fiddling with VS2008 and LINQ up until recently and this compact and short method works great for me (example is in VB.NET; requires LINQ / .NET FW 3.5+ of course):
直到最近,我一直在摆弄 VS2008 和 LINQ,这种紧凑而简短的方法对我很有用(示例在 VB.NET 中;当然需要 LINQ / .NET FW 3.5+):
Dim size As Int64 = (From strFile In My.Computer.FileSystem.GetFiles(strFolder, _
FileIO.SearchOption.SearchAllSubDirectories) _
Select New System.IO.FileInfo(strFile).Length).Sum()
Its short, it searches sub-directories and is simple to understand if you know LINQ syntax. You could even specify wildcards to search for specific files using the third parameter of the .GetFiles function.
它简短,它搜索子目录,如果您了解 LINQ 语法,则很容易理解。您甚至可以使用 .GetFiles 函数的第三个参数指定通配符来搜索特定文件。
I'm not a C# expert but you can add the My namespace on C# this way.
我不是 C# 专家,但您可以通过这种方式在 C# 上添加 My 命名空间。
I think this way of obtaining a folder size is not only shorter and more modern than the way described on Hao's link, it basically uses the same loop-of-FileInfo method described there in the end.
我认为这种获取文件夹大小的方式不仅比 Hao 的链接中描述的方式更短、更现代,而且基本上使用了最后描述的相同的 FileInfo 循环方法。
回答by Grozz
public static long DirSize(DirectoryInfo dir)
{
return dir.GetFiles().Sum(fi => fi.Length) +
dir.GetDirectories().Sum(di => DirSize(di));
}
回答by Bidou
To improve the performance, you could use the Task Parallel Library (TPL). Here is a good sample: Directory file size calculation - how to make it faster?
为了提高性能,您可以使用任务并行库 (TPL)。这是一个很好的示例:目录文件大小计算 - 如何使其更快?
I didn't test it, but the author says it is 3 times faster than a non-multithreaded method...
我没有测试它,但作者说它比非多线程方法快 3 倍......
回答by Alex
More faster! Add COM reference "Windows Script Host Object..."
更多更快!添加 COM 引用“Windows 脚本宿主对象...”
public double GetWSHFolderSize(string Fldr)
{
//Reference "Windows Script Host Object Model" on the COM tab.
IWshRuntimeLibrary.FileSystemObject FSO = new IWshRuntimeLibrary.FileSystemObject();
double FldrSize = (double)FSO.GetFolder(Fldr).Size;
Marshal.FinalReleaseComObject(FSO);
return FldrSize;
}
private void button1_Click(object sender, EventArgs e)
{
string folderPath = @"C:\Windows";
Stopwatch sWatch = new Stopwatch();
sWatch.Start();
double sizeOfDir = GetWSHFolderSize(folderPath);
sWatch.Stop();
MessageBox.Show("Directory size in Bytes : " + sizeOfDir + ", Time: " + sWatch.ElapsedMilliseconds.ToString());
}
回答by user541686
The real question is, what do you intend to use the size for?
真正的问题是,您打算将尺寸用于什么?
Your firstproblem is that there are at least fourdefinitions for "file size":
您的第一个问题是“文件大小”至少有四个定义:
The "end of file" offset, which is the number of bytes you have to skip to go from the beginning to the end of the file.
In other words, it is the number of bytes logicallyin the file (from a usage perspective).The "valid data length", which is equal to the offset of the first byte which is not actually stored.
This is always less than or equal to the "end of file", and is a multiple of the cluster size.
For example, a 1 GB file can have a valid data length of 1 MB. If you ask Windows to read the first 8 MB, it will read the first 1 MB and pretend the rest of the data was there, returning it as zeros.The "allocated size" of a file. This is always greater than or equal to the "end of file".
This is the number of clusters that the OS has allocated for the file, multiplied by the cluster size.
Unlike the case where the "end of file" is greater than the "valid data length", The excess bytes are notconsidered to be part of the file's data, so the OS will notfill a buffer with zeros if you try to read in the allocated region beyond the end of the file.The "compressed size" of a file, which is only valid for compressed (and sparse?) files.
It is equal to the size of a cluster, multiplied by the number of clusters on the volume that are actually allocatedto this file.
For non-compressed and non-sparse files, there is no notion of "compressed size"; you would use the "allocated size" instead.
“文件结尾”偏移量,它是从文件开头到结尾必须跳过的字节数。
换句话说,它是文件中逻辑上的字节数(从使用角度来看)。“有效数据长度”,等于未实际存储的第一个字节的偏移量。
这始终小于或等于“文件结尾”,并且是簇大小的倍数。
例如,一个 1 GB 的文件可以具有 1 MB 的有效数据长度。如果您要求 Windows 读取前 8 MB,它将读取前 1 MB 并假装其余数据在那里,将其返回为零。文件的“分配大小”。这总是大于或等于“文件结尾”。
这是操作系统为文件分配的簇数乘以簇大小。
与“文件结尾”大于“有效数据长度”的情况不同,多余的字节不被视为文件数据的一部分,因此如果您尝试读入,操作系统将不会用零填充缓冲区超出文件末尾的分配区域。文件的“压缩大小”,仅对压缩(和稀疏?)文件有效。
它等于簇的大小乘以卷上实际分配给该文件的簇数。
对于非压缩和非稀疏文件,没有“压缩大小”的概念;您将改用“分配的大小”。
Your secondproblem is that a "file" like C:\Foo
can actually have multiple streamsof data.
This name just refers to the defaultstream. A file might have alternatestreams, like C:\Foo:Bar
, whose size is not even shown in Explorer!
你的第二个问题是“文件”C:\Foo
实际上可以有多个数据流。
此名称仅指默认流。一个文件可能有备用流,比如C:\Foo:Bar
,其大小甚至没有显示在资源管理器中!
Your thirdproblem is that a "file" can have multiple names("hard links").
For example, C:\Windows\notepad.exe
and C:\Windows\System32\notepad.exe
are two namesfor the samefile. Anyname can be used to open anystream of the file.
您的第三个问题是“文件”可以有多个名称(“硬链接”)。
例如,C:\Windows\notepad.exe
并且C:\Windows\System32\notepad.exe
是两个名称的相同文件。 任何名称都可用于打开文件的任何流。
Your fourthproblem is that a "file" (or directory) might in fact not even be a file (or directory):
It might be a soft link(a "symbolic link" or a "reparse point") to some other file (or directory).
That other file might not even be on the same drive. It might even point to something on the network, or it might even be recursive! Should the size be infinity if it's recursive?
您的第四个问题是“文件”(或目录)实际上甚至可能不是文件(或目录):
它可能是指向其他文件的软链接(“符号链接”或“重新分析点”)(或目录)。
其他文件甚至可能不在同一个驱动器上。它甚至可能指向网络上的某些东西,或者它甚至可能是递归的!如果它是递归的,大小应该是无穷大吗?
Your fifthis that there are "filter" drivers that make certain files or directories looklike actual files or directories, even though they aren't. For example, Microsoft's WIM image files (which are compressed) can be "mounted" on a folder using a tool called ImageX, and those do notlook like reparse points or links. They look just like directories -- except that the're not actually directories, and the notion of "size" doesn't really make sense for them.
你的第五是有“过滤器”的驱动程序,使某些文件或目录看起来像实际的文件或目录,即使他们不是。例如,微软的WIM映像文件(压缩)可以“安装”使用一种称为ImageX工具的文件夹上,而那些没有像重分析点或链接。它们看起来就像目录——除了它们实际上不是目录,而且“大小”的概念对它们来说没有意义。
Your sixthproblem is that every file requires metadata.
For example, having 10 names for the same file requires more metadata, which requires space. If the file names are short, having 10 names might be as cheap as having 1 name -- and if they're long, then having multiple names can use more disk space for the metadata. (Same story with multiple streams, etc.)
Do you count these, too?
您的第六个问题是每个文件都需要元数据。
例如,同一文件有 10 个名称需要更多元数据,这需要空间。如果文件名很短,有 10 个名字可能和有 1 个名字一样便宜——如果文件名很长,那么有多个名字可以为元数据使用更多的磁盘空间。(同一个故事有多个流等等)
你也算这些吗?
回答by Trikaldarshi
DirectoryInfo dirInfo = new DirectoryInfo(@strDirPath);
long dirSize = await Task.Run(() => dirInfo.EnumerateFiles( "*", SearchOption.AllDirectories).Sum(file => file.Length));