在C#中获取文件大小

4
我想在ASP.Net中使用自定义处理程序将文件写回客户端,想知道用最少的处理时间完成此操作的最佳方法。目前我有两个不同版本的代码可以完成相同的操作,但由于处理程序将被频繁使用,我想知道最有效的方法是什么。
将完整文件加载到字节数组中,并使用BinaryWrite来写入文件:
string filePath = context.Server.MapPath(context.Request.Url.LocalPath);
Byte[] swfFile = File.ReadAllBytes(filePath);
context.Response.AppendHeader("content-length", Utils.MakeString(swfFile.Length));
context.Response.ContentType = Utils.GetMimeType(Path.GetExtension(filePath));
context.Response.BinaryWrite(swfFile);

使用 FileInfo 对象来确定文件长度和使用 TransmitFile 写入文件:
string filePath = context.Server.MapPath(context.Request.Url.LocalPath);
FileInfo fileInfo = new FileInfo(filePath);
context.Response.AppendHeader("content-length", Utils.MakeString(fileInfo.Length));
context.Response.ContentType = Utils.GetMimeType(Path.GetExtension(filePath));
context.Response.TransmitFile(filePath);

我认为TransmitFile方法是最有效的,因为它不需要缓冲文件就可以写入。那么FileInfo对象呢?它如何计算文件大小?使用FileInfo对象是最好的方法吗?还是有更好的方法?


我认为你可以尝试一个简单的方法。使用类似于 FileInfo f = new FileInfo(fileName); long s = f.Length; 的东西。 - Mihai8
2
FileInfo 只是询问文件系统(通常被认为是“昂贵”的,因为它会访问磁盘);这是获取大小的“最佳”方式。但第一种方法会在客户端下载文件所需的时间内将整个文件保存在内存中,这可能会成为一个巨大的问题。 - Jon
如果您无论如何都要读取文件(直接或间接),那么使用FileInfo查找文件长度的成本可以忽略不计 - 无论哪种方式,文件的目录条目都将被读取,并且它们将在操作系统的文件缓存中保留一段时间,因此获取文件大小时不会发生多次物理读取。 - Matthew Watson
在我看来,HttpResponse.TransmitFile() 的文档没有提到它是否会通知客户端消息边界(即设置Content-length头、执行分块、在传输后关闭连接)。我不希望在使用这种方法时需要显式地设置Content-length头,但我在文档中找不到相关信息。 - CodeCaster
@CodeCaster 很遗憾它本身不会添加 Content-length。我猜这是因为它边读边传输的缘故。 - nunespascal
1个回答

5
FileInfo会向文件系统询问文件大小信息(当然,它不需要读取所有内容来完成这个操作)。通常情况下,这被认为是一项“昂贵”的操作(与在内存中操纵数据和调用方法相比),因为它会访问磁盘。
然而,虽然减少磁盘访问确实是一件好事,但当您准备读取文件的全部内容时,这并不重要。所以你应该关注FileInfo本身的性能表现。
这里的主要问题是第一种方法“将整个文件保存在内存中,直到客户端下载完毕” - 这可能是一个巨大的问题,因为(根据文件大小和客户端连接的吞吐量),它有可能大大增加你的应用程序的内存使用量。如果这增加的内存使用量导致交换(即访问磁盘)的话,性能就会立刻下降。
所以你应该使用TransmitFile - 不是因为它更快地去访问磁盘(可能是或者不是),而是因为它使用的内存量更小。

1
你可能需要注意到FileInfo.Length是一个IO操作,但不需要通过读取所有字节来“测量”文件大小,我认为OP的问题是针对这个问题的(“它是如何计算文件大小的?”)。 - Tim Schmelter
@TimSchmelter:我认为“询问文件系统”已经暗示了这一点,但我还是加了一个明确的提醒。感谢您的反馈。 - Jon
询问文件系统也可能意味着文件系统在读取所有字节后才会回答;我认为请求 FileInfo.Length 就是右键单击文件并查看磁盘上大小属性时发生的相同操作。它只是读取文件上次修改时存储的内容。 - Tim Schmelter
@Jon:有趣的阅读!我在想FileInfo是否是检查磁盘上实际文件大小(而不是逻辑文件大小)的最佳性能方法?顺便说一下,我的用例全部在服务器端进行,没有涉及浏览器/客户端。 - Adam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接