我已编写以下例程来手动遍历目录并在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;
}
我有一个应用程序,它为大量文件夹重复运行此例程.我想知道是否有更有效的方法来计算.NET文件夹的大小?我没有在框架中看到任何具体内容.我应该使用P/Invoke和Win32 API吗?在.NET中计算文件夹大小的最有效方法是什么?
不,这看起来像计算目录大小的推荐方法,相关方法包括如下:
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; }
您可以使用root调用:
Console.WriteLine("The size is {0} bytes.", DirSize(new DirectoryInfo(targetFolder));
... targetFolder
要计算的文件夹大小在哪里.
我不相信有一个Win32 API来计算目录所占用的空间,虽然我有必要对此进行更正.如果有的话我会假设资源管理器会使用它.如果在资源管理器中获取大型目录的属性,则为您提供文件夹大小所需的时间与其包含的文件/子目录的数量成正比.
你的日常工作看起来相当简洁.请记住,您正在计算文件长度的总和,而不是磁盘上消耗的实际空间.群集,文件流等末尾的浪费空间所占用的空间将被忽略.
可以遵循最佳和最短的一种班轮方式
long length = Directory.GetFiles(directoryPath,"*",SearchOption.AllDirectories).Sum(t => (new FileInfo(t).Length));
您的第一个问题是"文件大小" 至少有四个定义:
"文件结束"偏移量,即从文件的开头到结尾必须跳过的字节数.
换句话说,它是文件中逻辑上的字节数(从使用角度来看).
"有效数据长度",等于实际未存储的第一个字节的偏移量.
这始终小于或等于"文件结尾",并且是簇大小的倍数.
例如,1 GB文件的有效数据长度为1 MB.如果您要求Windows读取前8 MB,它将读取前1 MB并假装其余数据存在,并将其作为零返回.
文件的"已分配大小".这始终大于或等于"文件结尾".
这是操作系统为文件分配的簇数乘以簇大小.
与"文件结尾"大于"有效数据长度"的情况不同,多余的字节不被视为文件数据的一部分,因此如果您尝试读取,操作系统将不会用零填充缓冲区超出文件末尾的已分配区域.
文件的"压缩大小",仅对压缩(和稀疏?)文件有效.
它等于群集的大小,乘以实际分配给此文件的卷上的群集数.
对于非压缩和非稀疏文件,没有"压缩大小"的概念; 你会用"分配大小"代替.
你的第二个问题是像"文件"一样C:\Foo
实际上可以有多个数据流.
此名称仅指默认流.一个文件可能有备用流,比如C:\Foo:Bar
,其大小甚至没有在资源管理器中显示!
你的第三个问题是"文件"可以有多个名称("硬链接").
例如,C:\Windows\notepad.exe
并且C:\Windows\System32\notepad.exe
是两个名称的相同文件. 任何名称都可用于打开文件的任何流.
你的第四个问题是"文件"(或目录)实际上甚至可能不是文件(或目录):
它可能是某个其他文件的软链接("符号链接"或"重新分析点")(或目录).
那个其他文件甚至可能不在同一个驱动器上.它甚至可能指向网络上的某些东西,或者它甚至可能是递归的!如果它是递归的,大小应该是无限的吗?
你的第五个是有"过滤器"驱动程序,使某些文件或目录看起来像实际文件或目录,即使它们不是.例如,微软的WIM映像文件(被压缩),可以使用一种称为ImageX工具文件夹中的"安装",而那些没有像重分析点或链接.它们看起来就像目录 - 除了它们实际上不是目录,而"大小"的概念对它们来说并没有意义.
您的第六个问题是每个文件都需要元数据.
例如,对同一文件具有10个名称需要更多元数据,这需要空间.如果文件名很短,那么拥有10个名称可能与拥有1个名称一样便宜 - 如果它们很长,那么拥有多个名称可以为元数据使用更多的磁盘空间.(同一个故事有多个流等等)
你也算这些吗?
public static long DirSize(DirectoryInfo dir) { return dir.GetFiles().Sum(fi => fi.Length) + dir.GetDirectories().Sum(di => DirSize(di)); }
var size = new DirectoryInfo("E:\\").GetDirectorySize();
这是Extension方法背后的代码
public static long GetDirectorySize(this System.IO.DirectoryInfo directoryInfo, bool recursive = true) { var startDirectorySize = default(long); if (directoryInfo == null || !directoryInfo.Exists) return startDirectorySize; //Return 0 while Directory does not exist. //Add size of files in the Current Directory to main size. foreach (var fileInfo in directoryInfo.GetFiles()) System.Threading.Interlocked.Add(ref startDirectorySize, fileInfo.Length); if (recursive) //Loop on Sub Direcotries in the Current Directory and Calculate it's files size. System.Threading.Tasks.Parallel.ForEach(directoryInfo.GetDirectories(), (subDirectory) => System.Threading.Interlocked.Add(ref startDirectorySize, GetDirectorySize(subDirectory, recursive))); return startDirectorySize; //Return full Size of this Directory. }
更多更快!添加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()); }