不使用System.IO.FileInfo获取文件大小
本文关键字:FileInfo 获取 文件大小 IO System | 更新日期: 2023-09-27 17:54:33
是否有可能在c#中不使用System.IO.FileInfo
而获得文件的大小 ?
我知道你可以得到其他的东西,如名称和扩展名分别使用Path.GetFileName(yourFilePath)
和Path.GetExtension(yourFilePath)
,但显然不是文件大小?有没有另一种方法我可以得到文件大小不使用System.IO.FileInfo
?
这样做的唯一原因是,如果我是正确的,FileInfo获取的信息比我真正需要的更多,因此,如果我唯一需要的是文件的大小,那么收集所有这些FileInfo需要更长的时间。有更快的方法吗?
我使用以下两种方法执行了一个基准测试:
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-63ms。GetFileSizeB耗时超过18秒。
除非有人看到我做错了什么,否则我认为答案是明确的,即哪种方法更快。
是否有一种方法可以避免实际打开文件?
FileAttributes变化。只读到文件属性。Normal减少了时间,使两种方法在性能上相同。
此外,如果您跳过CloseHandle()调用,GetFileSizeEx方法将变得大约快20-30%,尽管我不知道我是否建议这样做。
我做了一个简短的测试,我发现使用FileStream只比使用Pete的GetFileSizeB平均慢1毫秒(在网络共享上花了我大约21毫秒…)。就我个人而言,我更喜欢尽可能保持在BCL限制内。
代码很简单:
using (var file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return file.Length;
}
按照这个注释:
我有一个小的应用程序,收集大小信息,并保存到一个数组…但我经常有大约50万个文件,浏览所有这些文件需要一段时间(我用的是FileInfo)。我只是想知道是否有更快的方法…
因为你要找到这么多文件的长度,你更有可能从并行化中获益,而不是通过另一种方法获得文件大小。FileInfo
类应该足够好,任何改进都可能很小。
不是直接回答…因为我不确定是否有更快的方法来使用。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);
运行它,在我的"Program Files"目录上运行大约22720个文件花费了2709毫秒。无论如何,这都不是一个懒散的人。此外,当我将*.txt
作为GetFiles
方法的第一个参数的过滤器时,它将时间大幅减少到461ms。
这在很大程度上取决于你的硬盘有多快,但我真的不认为FileInfo会影响性能。
注意:我认为这只适用于。net 4+如果你想在非windows主机上的。net Core或Mono运行时这样做,一个快速的解决方案:
包含monox . 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系统调用(这个包是由微软维护的)。如果没有,结合其他基于P/调用的答案,以覆盖所有平台。
与FileInfo.Length
相比,当获得另一个进程/线程正在积极写入的文件的大小时,这给了我更可靠的结果。
你可以试试:
[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;
}