我已编写以下例程来手动遍历目录并在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中计算文件夹大小的最有效方法是什么?
hao*_*hao 58
不,这看起来像计算目录大小的推荐方法,相关方法包括如下:
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;
}
Run Code Online (Sandbox Code Playgroud)
您可以使用root调用:
Console.WriteLine("The size is {0} bytes.", DirSize(new DirectoryInfo(targetFolder));
Run Code Online (Sandbox Code Playgroud)
... targetFolder要计算的文件夹大小在哪里.
Mik*_*son 24
我不相信有一个Win32 API来计算目录所占用的空间,虽然我有必要对此进行更正.如果有的话我会假设资源管理器会使用它.如果在资源管理器中获取大型目录的属性,则为您提供文件夹大小所需的时间与其包含的文件/子目录的数量成正比.
你的日常工作看起来相当简洁.请记住,您正在计算文件长度的总和,而不是磁盘上消耗的实际空间.群集,文件流等末尾的浪费空间所占用的空间将被忽略.
Tri*_*shi 22
可以遵循最佳和最短的一种班轮方式
long length = Directory.GetFiles(directoryPath,"*",SearchOption.AllDirectories).Sum(t => (new FileInfo(t).Length));
Run Code Online (Sandbox Code Playgroud)
Meh*_*dad 15
您的第一个问题是"文件大小" 至少有四个定义:
"文件结束"偏移量,即从文件的开头到结尾必须跳过的字节数.
换句话说,它是文件中逻辑上的字节数(从使用角度来看).
"有效数据长度",等于实际未存储的第一个字节的偏移量.
这始终小于或等于"文件结尾",并且是簇大小的倍数.
例如,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个名称一样便宜 - 如果它们很长,那么拥有多个名称可以为元数据使用更多的磁盘空间.(同一个故事有多个流等等)
你也算这些吗?
Gro*_*ozz 14
public static long DirSize(DirectoryInfo dir)
{
return dir.GetFiles().Sum(fi => fi.Length) +
dir.GetDirectories().Sum(di => DirSize(di));
}
Run Code Online (Sandbox Code Playgroud)
看起来,以下方法比递归函数更快地执行您的任务:
long size = 0;
DirectoryInfo dir = new DirectoryInfo(folder);
foreach (FileInfo fi in dir.GetFiles("*.*", SearchOption.AllDirectories))
{
size += fi.Length;
}
Run Code Online (Sandbox Code Playgroud)
一个简单的控制台应用程序测试表明,该循环比递归函数更快地求和文件,并提供相同的结果。并且您可能希望使用 LINQ 方法(如 Sum())来缩短此代码。
var size = new DirectoryInfo("E:\\").GetDirectorySize();
Run Code Online (Sandbox Code Playgroud)
这是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.
}
Run Code Online (Sandbox Code Playgroud)
更多更快!添加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());
}
Run Code Online (Sandbox Code Playgroud)
我使用相同的计数原理扩展了 @Hao 的答案,但支持更丰富的数据返回,因此您可以返回大小、递归大小、目录计数和递归目录计数,深度为 N 层。
public class DiskSizeUtil
{
/// <summary>
/// Calculate disk space usage under <paramref name="root"/>. If <paramref name="levels"/> is provided,
/// then return subdirectory disk usages as well, up to <paramref name="levels"/> levels deep.
/// If levels is not provided or is 0, return a list with a single element representing the
/// directory specified by <paramref name="root"/>.
/// </summary>
/// <returns></returns>
public static FolderSizeInfo GetDirectorySize(DirectoryInfo root, int levels = 0)
{
var currentDirectory = new FolderSizeInfo();
// Add file sizes.
FileInfo[] fis = root.GetFiles();
currentDirectory.Size = 0;
foreach (FileInfo fi in fis)
{
currentDirectory.Size += fi.Length;
}
// Add subdirectory sizes.
DirectoryInfo[] dis = root.GetDirectories();
currentDirectory.Path = root;
currentDirectory.SizeWithChildren = currentDirectory.Size;
currentDirectory.DirectoryCount = dis.Length;
currentDirectory.DirectoryCountWithChildren = dis.Length;
currentDirectory.FileCount = fis.Length;
currentDirectory.FileCountWithChildren = fis.Length;
if (levels >= 0)
currentDirectory.Children = new List<FolderSizeInfo>();
foreach (DirectoryInfo di in dis)
{
var dd = GetDirectorySize(di, levels - 1);
if (levels >= 0)
currentDirectory.Children.Add(dd);
currentDirectory.SizeWithChildren += dd.SizeWithChildren;
currentDirectory.DirectoryCountWithChildren += dd.DirectoryCountWithChildren;
currentDirectory.FileCountWithChildren += dd.FileCountWithChildren;
}
return currentDirectory;
}
public class FolderSizeInfo
{
public DirectoryInfo Path { get; set; }
public long SizeWithChildren { get; set; }
public long Size { get; set; }
public int DirectoryCount { get; set; }
public int DirectoryCountWithChildren { get; set; }
public int FileCount { get; set; }
public int FileCountWithChildren { get; set; }
public List<FolderSizeInfo> Children { get; set; }
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
这个解决方案效果很好。它正在收集所有子文件夹:
Directory.GetFiles(@"MainFolderPath", "*", SearchOption.AllDirectories).Sum(t => (new FileInfo(t).Length));
Run Code Online (Sandbox Code Playgroud)
Trikaldarshi 的单线解决方案的替代方案。(它避免了构造 FileInfo 对象)
long sizeInBytes = Directory.EnumerateFiles("{path}","*", SearchOption.AllDirectories).Sum(fileInfo => new FileInfo(fileInfo).Length);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
84640 次 |
| 最近记录: |