简体   繁体   English

在不使用 System.IO.FileInfo 的情况下获取文件大小?

[英]Get file size without using System.IO.FileInfo?

Is it possible to get the size of a file in C# without using System.IO.FileInfo at all?是否可以在不使用System.IO.FileInfo情况下在 C# 中获取文件的大小

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?我知道您可以通过分别使用Path.GetFileName(yourFilePath)Path.GetExtension(yourFilePath)来获得名称和扩展名等其他内容,但显然不是文件大小? Is there another way I can get file size without using System.IO.FileInfo ?有没有另一种方法可以在不使用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.这样做的唯一原因是,如果我是对的,FileInfo 获取的信息比我真正需要的要多,因此,如果我唯一需要的是文件的大小,则收集所有这些 FileInfo 的时间会更长。 Is there a faster way?有没有更快的方法?

I performed a benchmark using these two methods:我使用这两种方法进行了基准测试:

    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;
    }

Running against a bit over 2300 files, GetFileSizeA took 62-63ms to run.运行 2300 多个文件,GetFileSizeA 需要 62-63 毫秒才能运行。 GetFileSizeB took over 18 seconds. GetFileSizeB 耗时超过 18 秒。

Unless someone sees something I'm doing wrong, I think the answer is clear as to which method is faster.除非有人看到我做错了什么,否则我认为哪种方法更快的答案很清楚。

Is there a way I can refrain from actually opening the file?有没有办法避免实际打开文件?

Update更新

Changing FileAttributes.ReadOnly to FileAttributes.Normal reduced the timing so that the two methods were identical in performance.将 FileAttributes.ReadOnly 更改为 FileAttributes.Normal 减少了时间,因此这两种方法的性能相同。

Furthermore, if you skip the CloseHandle() call, the GetFileSizeEx method becomes about 20-30% faster, though I don't know that I'd recommend that.此外,如果您跳过 CloseHandle() 调用,GetFileSizeEx 方法会变得快 20-30%,尽管我不知道我会推荐这样做。

From a short test i did, i've found that using a FileStream is just 1 millisecond slower in average than using Pete's GetFileSizeB (took me about 21 milliseconds over a network share...).从我做的一个简短的测试中,我发现使用 FileStream 平均只比使用 Pete 的 GetFileSizeB 慢 1 毫秒(通过网络共享花了我大约 21 毫秒......)。 Personally i prefer staying within the BCL limits whenever i can.我个人更喜欢尽可能保持在 BCL 限制内。

The code is simple:代码很简单:

using (var file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    return file.Length;
}

As per this comment :根据此评论

I have a small application that gathers the size info and saves it into an array... but I often have half a million files, give or take and that takes a while to go through all of those files (I'm using FileInfo).我有一个小应用程序,它收集大小信息并将其保存到一个数组中......但我经常有 50 万个文件,给予或接受并且需要一段时间来浏览所有这些文件(我正在使用 FileInfo) . I was just wondering if there was a faster way...我只是想知道是否有更快的方法...

Since you're finding the length of so many files you're much more likely to benefit from parallelization than from trying to get the file size through another method.由于您要找到如此多文件的长度,因此与尝试通过另一种方法获取文件大小相比,并行化更有可能受益。 The FileInfo class should be good enough , and any improvements are likely to be small. FileInfo类应该足够好,任何改进都可能很小。

Parallelizing the file size requests, on the other hand, has the potential for significant improvements in speed.另一方面,并​​行处理文件大小请求有可能显着提高速度。 (Note that the degree of improvement will be largely based on your disk drive, not your processor, so results can vary greatly.) (请注意,改进程度将主要取决于您的磁盘驱动器,而不是您的处理器,因此结果可能会有很大差异。)

Not a direct answer...because I am not sure there is a faster way using the .NET framework.不是直接的答案...因为我不确定使用 .NET 框架是否有更快的方法。

Here's the code I am using:这是我正在使用的代码:

  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);

Running that, it took 2709ms to run on my "Program Files" directory, which was around 22720 files.运行它,在我的“程序文件”目录上运行需要 2709 毫秒,大约有 22720 个文件。 That's no slouch by any means.这绝不是懈怠。 Furthermore, when I put *.txt as a filter for the first parameter of the GetFiles method, it cut the time down drastically to 461ms.此外,当我将*.txt作为GetFiles方法的第一个参数的过滤器时,它将时间大幅减少到 461 毫秒。

A lot of this will depend on how fast your hard drive is, but I really don't think that FileInfo is killing performance.这很大程度上取决于您的硬盘驱动器的速度,但我真的不认为 FileInfo 会降低性能。

NOTE: I thikn this only valid for .NET 4+注意:我认为这仅对 .NET 4+ 有效

A quick'n'dirty solution if you want to do this on the .NET Core or Mono runtimes on non-Windows hosts:如果您想在非 Windows 主机上的 .NET Core 或 Mono 运行时上执行此操作,这是一个快速的解决方案:

Include the Mono.Posix.NETStandard NuGet package, then something like this...包括Mono.Posix.NETStandard NuGet 包,然后像这样......

using Mono.Unix.Native;

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

I've tested this running .NET Core on Linux and macOS - not sure if it works on Windows - it might, given that these are POSIX syscalls under the hood (and the package is maintained by Microsoft).我已经在 Linux 和 macOS 上测试了这个运行 .NET Core - 不确定它是否适用于 Windows - 它可能,因为这些是引擎盖下的 POSIX 系统调用(并且包由 Microsoft 维护)。 If not, combine with the other P/Invoke-based answer to cover all platforms.如果没有,请结合其他基于 P/Invoke 的答案以涵盖所有平台。

When compared to FileInfo.Length , this gives me much more reliable results when getting the size of a file that is actively being written to by another process/thread.FileInfo.Length相比,在获取另一个进程/线程正在积极写入的文件的大小时,这给了我更可靠的结果。

You can try this:你可以试试这个:

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

But that's not much of an improvement...但这并没有太大的改善......

Here's the example code taken from pinvoke.net:这是摘自 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从c#中的System.Linq.Enumerable + WhereArrayIterator`1 [System.IO.FileInfo]变量中获取所有文件名? - how to get all file name from System.Linq.Enumerable+WhereArrayIterator`1[System.IO.FileInfo] variable in c#? System.IO.File和System.IO.FileInfo有什么区别 - What is the difference between System.IO.File and System.IO.FileInfo 我如何 MOQ System.IO.FileInfo 类...或任何其他没有接口的类? - How do I MOQ the System.IO.FileInfo class… or any other class without an interface? 参数2:无法从System.IO.FileInfo转换为“字符串” - Argument 2: cannot convert from System.IO.FileInfo to 'string' 参数 1:无法从 System.IO.FileInfo 转换为“字符串” - Argument 1: cannot convert from System.IO.FileInfo to 'string' &#39;System.IO.FileInfo&#39;不包含&#39;GetFiles&#39;的定义 - 'System.IO.FileInfo' does not contain a definition for 'GetFiles' 如何转换List的类型 <System.IO.FileInfo> 列表 <string> ? - How convert type of List<System.IO.FileInfo> to List<string>? 无法从“System.IO.FileInfo”转换为字符串 - cannot convert from “System.IO.FileInfo” to string C#无法将类型&#39;System.IO.FileInfo&#39;隐式转换为字符串 - C# Cannot Implicitly Convert type 'System.IO.FileInfo' to string 在WIX自定义操作中使用System.IO.FileInfo将意外的字符串添加到路径 - System.IO.FileInfo adds unexpected string to path when used in WIX Custom Action
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM