You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8中如何获取Microsoft Scripting Runtime实现文件夹大小计算?

Windows平台下.NET快速统计文件夹大小的优化方案

关于"Microsoft Scripting Runtime"的说明

你看到的旧方案依赖的是COM组件Microsoft Scripting Runtime,在现代.NET(.NET Core/.NET 5+)环境中确实不再作为默认引用存在,而且COM互操作的性能远不如原生.NET方法,完全没必要继续纠结这个组件。

更快的底层实现方案

1. 直接调用Windows原生文件系统API(FindFirstFileEx/FindNextFile)

这是最贴近底层的实现方式,绕开.NET托管封装的额外开销,直接与Windows文件系统交互,性能最优。通过P/Invoke调用这些API,能避免托管代码的冗余逻辑,适合对性能要求极高的场景。

示例代码:

using System;
using System.Runtime.InteropServices;

public static class FolderSizeCalculator
{
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    private struct WIN32_FIND_DATA
    {
        public uint dwFileAttributes;
        public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
        public uint nFileSizeHigh;
        public uint nFileSizeLow;
        public uint dwReserved0;
        public uint dwReserved1;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string cFileName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
        public string cAlternateFileName;
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern IntPtr FindFirstFileEx(string lpFileName, int fInfoLevelId, out WIN32_FIND_DATA lpFindFileData, int fSearchOp, IntPtr lpSearchFilter, int dwAdditionalFlags);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool FindClose(IntPtr hFindFile);

    private const int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
    private const int FINDEX_INFO_LEVELS = 0; // FindExInfoStandard
    private const int FINDEX_SEARCH_OPS = 0; // FindExSearchNameMatch

    public static long CalculateFolderSize(string folderPath)
    {
        long totalSize = 0;
        string searchPattern = Path.Combine(folderPath, "*");

        IntPtr findHandle = FindFirstFileEx(searchPattern, FINDEX_INFO_LEVELS, out WIN32_FIND_DATA findData, FINDEX_SEARCH_OPS, IntPtr.Zero, 0);
        if (findHandle == IntPtr.Zero)
            return totalSize;

        try
        {
            do
            {
                if (findData.cFileName == "." || findData.cFileName == "..")
                    continue;

                if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
                {
                    string subFolderPath = Path.Combine(folderPath, findData.cFileName);
                    totalSize += CalculateFolderSize(subFolderPath);
                }
                else
                {
                    long fileSize = (long)findData.nFileSizeHigh << 32 | findData.nFileSizeLow;
                    totalSize += fileSize;
                }
            } while (FindNextFile(findHandle, out findData));
        }
        finally
        {
            FindClose(findHandle);
        }

        return totalSize;
    }
}

2. 优化.NET原生枚举的并行遍历

如果不想编写P/Invoke代码,可以对现有.NET方法做进一步优化。比如用Parallel.ForEach并行遍历文件,但要注意磁盘类型:SSD适合并行处理,机械硬盘可能因磁头频繁切换导致性能下降,需根据实际环境选择。

示例代码:

using System;
using System.IO;
using System.Threading;

public static long FastCalculateFolderSize(string folderPath)
{
    long totalSize = 0;
    var files = Directory.EnumerateFiles(folderPath, "*", SearchOption.AllDirectories);
    
    Parallel.ForEach(files, file =>
    {
        try
        {
            var fileInfo = new FileInfo(file);
            Interlocked.Add(ref totalSize, fileInfo.Length);
        }
        catch (UnauthorizedAccessException)
        {
            // 处理无权限访问的文件,直接跳过
        }
        catch (FileNotFoundException)
        {
            // 处理遍历中被删除的文件,直接跳过
        }
    });
    
    return totalSize;
}

3. 利用Windows USN日志(进阶方案)

如果需要频繁统计文件夹大小,可以利用Windows的更新序列号(USN)日志——它会记录文件系统的变更信息,能快速获取文件大小的变化,避免每次全量遍历。不过这个方案实现复杂,仅适合高频统计的特定场景。

注意事项

  • 异常处理:遍历文件夹时必须处理UnauthorizedAccessException、FileNotFoundException等异常,避免程序崩溃。
  • 磁盘缓存:第一次统计后系统会缓存文件信息,后续统计速度会明显提升,测试时要区分冷启动和热启动的差异。
  • 符号链接:如果需要处理符号链接,要在代码中判断并决定是否跟随链接,避免无限递归或重复统计内容。

内容的提问来源于stack exchange,提问作者jc508

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 02:58:22