13

Is it possible to get the size of a file in C# without using System.IO.FileInfo at all?

I know that you can get other things like Name and Extension by using Path.GetFileName(yourFilePath) and Path.GetExtension(yourFilePath) respectively, but apparently not file size? Is there another way I can get file size without using System.IO.FileInfo?

The only reason for this is that, if I'm correct, FileInfo grabs more info than I really need, therefore it takes longer to gather all those FileInfo's if the only thing I need is the size of the file. Is there a faster way?

4

6 回答 6

8

我使用这两种方法进行了基准测试:

    public static uint GetFileSizeA(string filename)
    {
        WIN32_FIND_DATA findData;
        FindFirstFile(filename, out findData);
        return findData.nFileSizeLow;
    }

    public static uint GetFileSizeB(string filename)
    {
        IntPtr handle = CreateFile(
            filename,
            FileAccess.Read,
            FileShare.Read,
            IntPtr.Zero,
            FileMode.Open,
            FileAttributes.ReadOnly,
            IntPtr.Zero);
        long fileSize;
        GetFileSizeEx(handle, out fileSize);
        CloseHandle(handle);
        return (uint) fileSize;
    }

运行超过 2300 个文件,GetFileSizeA 需要 62-63 毫秒才能运行。GetFileSizeB 花费了 18 秒。

除非有人看到我做错了什么,否则我认为答案很清楚,哪种方法更快。

有没有办法可以避免实际打开文件?

更新

将 FileAttributes.ReadOnly 更改为 FileAttributes.Normal 减少了时间,因此这两种方法的性能相同。

此外,如果您跳过 CloseHandle() 调用,GetFileSizeEx 方法的速度会提高大约 20-30%,尽管我不知道我是否会建议这样做。

于 2013-01-18T22:41:47.597 回答
5

从我做的一个简短测试中,我发现使用 FileStream 平均比使用 Pete 的 GetFileSizeB 慢 1 毫秒(通过网络共享花了我大约 21 毫秒......)。就我个人而言,我更喜欢尽可能保持在 BCL 范围内。

代码很简单:

using (var file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    return file.Length;
}
于 2013-12-19T09:19:48.340 回答
3

不是直接的答案...因为我不确定使用 .NET 框架是否有更快的方法。

这是我正在使用的代码:

  List<long> list = new List<long>();
  DirectoryInfo di = new DirectoryInfo("C:\\Program Files");
  FileInfo[] fiArray = di.GetFiles("*", SearchOption.AllDirectories);
  foreach (FileInfo f in fiArray)
    list.Add(f.Length);

运行它,在我的“程序文件”目录上运行了 2709 毫秒,大约有 22720 个文件。无论如何,这绝不是懈怠。此外,当我*.txt将该方法的第一个参数用作过滤器时GetFiles,它会将时间大幅缩短至 461 毫秒。

这在很大程度上取决于您的硬盘驱动器的速度,但我真的不认为 FileInfo 会影响性能。

注意:我认为这仅对 .NET 4+ 有效

于 2013-02-13T20:21:45.327 回答
3

根据此评论

我有一个小型应用程序,它收集大小信息并将其保存到一个数组中......但我经常有半百万个文件,给予或接受,并且需要一段时间才能浏览所有这些文件(我正在使用 FileInfo) . 我只是想知道是否有更快的方法...

由于您发现了这么多文件的长度,因此您更有可能从并行化中受益,而不是尝试通过另一种方法获取文件大小。该类FileInfo应该足够好,并且任何改进都可能很小。

另一方面,并​​行化文件大小请求有可能显着提高速度。(请注意,改进程度很大程度上取决于您的磁盘驱动器,而不是您的处理器,因此结果可能会有很大差异。)

于 2013-01-18T22:16:04.213 回答
1

如果您想在非 Windows 主机上的 .NET Core 或 Mono 运行时上执行此操作,这是一个快速的解决方案:

包括Mono.Posix.NETStandard NuGet 包,然后是这样的......

using Mono.Unix.Native;

private long GetFileSize(string filePath)
{
    Stat stat;
    Syscall.stat(filePath, out stat);
    return stat.st_size;
}

我已经在 Linux 和 macOS 上测试了这个正在运行的 .NET Core - 不确定它是否适用于 Windows - 考虑到这些是 POSIX 系统调用(并且包由 Microsoft 维护),它可能会。如果没有,请结合其他基于 P/Invoke 的答案以涵盖所有平台。

与 相比FileInfo.Length,当获取另一个进程/线程正在写入的文件的大小时,这给了我更可靠的结果。

于 2020-01-20T02:36:05.493 回答
0

你可以试试这个:

[DllImport("kernel32.dll")]
static extern bool GetFileSizeEx(IntPtr hFile, out long lpFileSize);

但这并没有太大的改善...

以下是从 pinvoke.net 获取的示例代码:

IntPtr handle = CreateFile(
    PathString, 
    GENERIC_READ, 
    FILE_SHARE_READ, 
    0, 
    OPEN_EXISTING, 
    FILE_ATTRIBUTE_READONLY, 
    0); //PInvoked too

if (handle.ToInt32() == -1) 
{
    return; 
}

long fileSize;
bool result = GetFileSizeEx(handle, out fileSize);
if (!result) 
{
    return;
}
于 2013-01-18T21:33:55.610 回答