在C#中将大文件读入字节数组的最佳方法是什么?

我有一个Web服务器,它将读取大的二进制文件(几兆字节)成字节数组。 服务器可能会同时读取多个文件(不同的页面请求),所以我正在寻找最优化的方式来做到这一点,而不用过多的CPU。 代码是否足够好?

public byte[] FileToByteArray(string fileName) { byte[] buff = null; FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); BinaryReader br = new BinaryReader(fs); long numBytes = new FileInfo(fileName).Length; buff = br.ReadBytes((int) numBytes); return buff; } 

简单地用以下代替整个事物:

 return File.ReadAllBytes(fileName); 

但是,如果您担心内存消耗, 则不应将整个文件一次全部读入内存。 你应该这样做大块。

我可能会说这里的答案一般是“不”。 除非您绝对需要所有的数据,否则请考虑使用基于Stream的API(或读取器/迭代器的一些变体)。 当你有多个并行操作(如问题所build议的)时,这是特别重要的,以最大限度地减less系统负载和最大化吞吐量。

例如,如果您正在将数据传输到呼叫者:

 Stream dest = ... using(Stream source = File.OpenRead(path)) { byte[] buffer = new byte[2048]; int bytesRead; while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) { dest.Write(buffer, 0, bytesRead); } } 

我会这样想:

 byte[] file = System.IO.File.ReadAllBytes(fileName); 

你的代码可以考虑到这个(代替File.ReadAllBytes):

 public byte[] ReadAllBytes(string fileName) { byte[] buffer = null; using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { buffer = new byte[fs.Length]; fs.Read(buffer, 0, (int)fs.Length); } return buffer; } 

请注意Integer.MaxValue – 由Read方法放置的文件大小限制。 换句话说,你只能读一个2GB的块。

另请注意,FileStream的最后一个参数是缓冲区大小。

我也build议阅读关于FileStream和BufferedStream 。

一如往常,一个简单的示例程序来分析哪个是最快的将是最有利的。

而且你的底层硬件也会对性能有很大的影响。 您是否正在使用基于服务器的大型caching硬盘驱动器和带有板载内存caching的RAID卡? 还是你使用连接到IDE端口的标准驱动器?

根据操作频率,文件大小以及您正在查看的文件数量,还有其他性能问题需要考虑。 有一件事要记住,是你的每个字节数组都将在垃圾回收器的摆布下释放。 如果您没有caching任何这些数据,那么最终可能会造成大量垃圾,并将大部分性能损失到GC中的%Time 。 如果块大于85K,你将分配给大对象堆(LOH),这将需要收集所有的世代来释放(这是非常昂贵的,并在服务器上将停止所有执行,而它正在进行)。 此外,如果在LOH上有大量的对象,则可能会导致LOH碎片化(LOH从不压缩),从而导致性能下降和内存不足exception。 一旦你遇到某个问题,你可以回收这个过程,但是我不知道这是否是最佳做法。

重点是,你应该考虑你的应用程序的整个生命周期,必须尽可能以最快的方式将所有的字节读入内存,否则你可能会为整体性能交易短期性能。

我会说, BinaryReader是好的,但可以重构为此,而不是所有这些代码行来获取缓冲区的长度:

 public byte[] FileToByteArray(string fileName) { byte[] fileData = null; using (FileStream fs = new File.OpenRead(fileName)) { using (BinaryReader binaryReader = new BinaryReader(fs)) { fileData = binaryReader.ReadBytes((int)fs.Length); } } return fileData; } 

应该比使用.ReadAllBytes()更好,因为我在包含.ReadAllBytes()的顶级响应的注释中看到,其中一个评论者对文件大于600 MB有问题,因为BinaryReader是用于这类事情的。 另外,把它放在using语句中,可以确保FileStreamBinaryReader被closures和处理。

使用C#中的BufferedStream类来提高性能。 缓冲区是内存中用于caching数据的字节块,从而减less了对操作系统的调用次数。 缓冲区提高了读写性能。

请参阅以下代码示例和其他说明: http : //msdn.microsoft.com/en-us/library/system.io.bufferedstream.aspx

我会build议尝试Response.TransferFile()方法,然后Response.Flush()Response.End()为您的大型文件。

如果您处理的文件大于2 GB,则会发现上述方法失败。

把stream传递给MD5并允许为你的文件分块是很容易的:

 private byte[] computeFileHash(string filename) { MD5 md5 = MD5.Create(); using (FileStream fs = new FileStream(filename, FileMode.Open)) { byte[] hash = md5.ComputeHash(fs); return hash; } }