Get file size without using System.IO.FileInfo?

2019-03-25 03:14发布

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?

5条回答
爷、活的狠高调
2楼-- · 2019-03-25 03:58

Not a direct answer...because I am not sure there is a faster way using the .NET framework.

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. 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.

A lot of this will depend on how fast your hard drive is, but I really don't think that FileInfo is killing performance.

NOTE: I thikn this only valid for .NET 4+

查看更多
一夜七次
3楼-- · 2019-03-25 04:04

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:

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;
}
查看更多
不美不萌又怎样
4楼-- · 2019-03-25 04:07

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...). Personally i prefer staying within the BCL limits whenever i can.

The code is simple:

using (var file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    return file.Length;
}
查看更多
姐就是有狂的资本
5楼-- · 2019-03-25 04:11

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

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

查看更多
三岁会撩人
6楼-- · 2019-03-25 04:17

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. GetFileSizeB took over 18 seconds.

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.

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.

查看更多
登录 后发表回答