我正在编写一个 32 位 c# 应用程序,它通过从 kernal32.dll FindFirstFile 获取文件信息来返回目录的整体大小。这战胜了以常规方式枚举每个目录,并且我能够将资源使用率保持在极低的水平。
其工作原理的快速概述如下:
- 第 1 步 - 枚举根目录获取所有子目录并使用 FindFirstFile 收集此目录中每个文件的大小信息。
- 第 2 步 - 生成子线程(最多 20 个)以针对子目录执行第 1 步
- 第 3 步 - 递归直到用尽目录并收集所有文件信息。
这可以在以下代码示例中看到,其中 FileSystem.GetFiles 是我的类,它利用 kernal32 方法获取文件信息。
private static void recurseDirectories(string directoryA, bool paramInitialPass)
{
try
{
string[] currentDirs;
if (paramInitialPass)
{
currentDirs = new string[1];
currentDirs[0] = rootDirectory;
}
else
currentDirs = Directory.GetDirectories(directoryA);
for (int i = 0; i < currentDirs.Length; i++)
{
string threadInfo = currentDirs[i];
numThreadsQueued++;
ThreadPool.QueueUserWorkItem(new WaitCallback(getDirectoryFileInformation), (object)threadInfo);
while (numThreadsQueued - directoriesProcessed > 20)
{
Thread.Sleep(30);
}
if (paramInitialPass)
recurseDirectories(directoryA, false);
else
recurseDirectories(currentDirs[i], false);
}
}
catch
{
}
return;
}
private static void getDirectoryFileInformation(object paramDirectoryFilePathA)
{
try
{
string directoryPathA = (string)paramDirectoryFilePathA;
List<FileData> filesDirectoryA = new List<FileData>();
if (Directory.Exists(directoryPathA))
{
filesDirectoryA = FileSystem.GetFiles(directoryPathA);
}
foreach(FileData file in filesDirectoryA)
{
Interlocked.Add(ref sizeOfFiles, file.Size);
Interlocked.Increment(ref numberOfFiles);
}
}
catch (Exception e)
{
}
finally
{
Interlocked.Increment(ref directoriesProcessed);
}
}
使用以下代码调用这两个方法:
ThreadPool.SetMaxThreads(30, 500);
Thread.CurrentThread.Priority = ThreadPriority.Normal;
rootDirectory = share["Path"].ToString();
recurseDirectories(share["Path"].ToString(), true);
while (numThreadsQueued != directoriesProcessed)
{
Thread.Sleep(1000);
}
此代码在枚举大多数目录时表现完美。我能够递归 3TB 文件共享,在大约 8 分钟内获得总文件大小和文件数量,同时将 cpu 保持在 3% 以下并使用 15MB 内存。
现在问题来了...
在获取小目录(1-200 GB)的大小时,我看不到 Windows 在查看目录属性时所说的任何重大差异。但是,我注意到在获取大目录(2-3TB)的大小时存在一些主要差异。
例如:
假设我正在查看 DFSR 复制到另一台服务器的目录 D:\TestDir。Windows 说这个目录是 2,949,944,019,217 字节,或磁盘上的 2,974,186,774,528 字节(分别为 2.68 TB 或 2.70 TB)。我的程序说这个目录是 3,009,619,048,759 字节或 2.737 TB。FSRM 说同一目录上的配额设置有 2.71 TB 的使用量。
我知道差异部分是由于 Windows 的大小不包括隐藏文件,但是当我将目录中隐藏文件的总大小 (87GB) 添加到 Windows 值时,我得到 ~2.78 GB,这仍然与我的值不同。任何人都可以阐明我造成这些尺寸差异的其他原因吗?另外,有谁知道 FSRM 如何确定配额使用情况?
最终,我想用一个使用我的数据的监控系统替换 FSRM 配额,但如果我的数据与 Windows 所说的不相符,我可能会收到有关磁盘使用情况的错误警报。