在C#中将大文件读入字节数组的最佳方法是什么?
在C#中将大文件读入字节数组的最佳方法是什么?
我有一个Web服务器,它会将大型二进制文件(几兆字节)读取到字节数组中。服务器可能同时读取多个文件(不同的页面请求),因此我正在寻找在不过多占用CPU资源的情况下进行此操作的最优化方法。下面的代码是否足够好? \n
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; }
在C#中,将大文件读入字节数组的最佳方法是什么?
有一个简单的方法可以实现这个目标:
byte[] file = System.IO.File.ReadAllBytes(fileName);
值得注意的是,当处理非常大的文件时,这种方法可能会导致程序停顿。
那么为什么会出现这个问题?原因是在使用System.IO.File.ReadAllBytes方法读取大文件时,它会一次性将整个文件读入内存,这可能会导致内存溢出或导致程序的性能下降。
为了解决这个问题,我们可以使用流来读取文件的一部分,并将其写入字节数组。这样可以避免将整个文件加载到内存中,从而提高性能并避免内存溢出。
以下是一个解决方法的示例代码:
const int bufferSize = 4096; // 缓冲区大小 byte[] file; using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { using (BinaryReader br = new BinaryReader(fs)) { long numBytes = new FileInfo(fileName).Length; // 文件大小 long remainingBytes = numBytes; file = new byte[numBytes]; // 创建字节数组 while (remainingBytes > 0) { int bytesRead = br.Read(file, (int)(numBytes - remainingBytes), bufferSize); // 从文件流中读取字节到数组中 remainingBytes -= bytesRead; } } }
通过使用流和缓冲区,我们可以逐步读取文件的一部分,并将其写入字节数组中。这种方法可以有效地处理大文件,并避免程序停顿或内存溢出的问题。
大文件读取为字节数组在C#中的最佳方法是什么?
在这里,我可能会认为答案通常是“不要这样做”。除非您绝对需要一次性获取所有数据,否则请考虑使用基于流的API(或一些读取器/迭代器的变体)。这在您有多个并行操作(如问题中所述)时尤为重要,以减少系统负载并最大化吞吐量。
例如,如果您正在将数据流式传输给调用方:
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); } }
补充一下,如果您有像向客户端流式传输文件这样的I/O绑定操作,则可以考虑使用异步ASP.NET处理程序。但是,如果由于某种原因您必须将整个文件读取到byte[]
中,我建议避免使用流或任何其他东西,只需使用系统提供的API。
- 同意;但是完整的上下文不清楚。同样,MVC有用于此的操作结果。
是的,我需要一次性获取所有数据。它将发送到第三方Web服务。
系统提供的API是什么?
:我在我的答案中已经说明了:File.ReadAllBytes
。
我如何使用它将数据写入另一个字节数组中?
通过每次更改offset
来增加读取的字节数量,并通过相同数量递减要读取的数量(从bytesToRead = target.Length
开始);因此:int offset = 0; int toRead = target.Length; while ((bytesRead - source.Read(target, offset, toRead)) > 0) { offset += bytesRead; toRead -= bytesRead; }
但是,当我尝试提前从源中获取长度时,代码会中断并出现SystemOutOfMemory异常。
您能展示一下您在那里做什么的代码吗?数据流有多大?是的:如果您尝试一次性将所有内容加载到内存中,它可能会爆炸;尤其是对于超过约800MiB的内容。
在您的评论中,“系统提供的API”是什么意思?
解决大文件读取到字节数组的最佳方法是使用File.ReadAllBytes方法。但是,如果担心内存消耗,应该避免一次性将整个文件读取到内存中,而应该分块读取。
File.ReadAllBytes方法在读取超过2^32字节(4.2GB)的文件时会抛出OutOfMemoryException异常。因此,对于大文件,不适合使用这种方法。
根据一位用户的建议,应该使用流的方式读取文件,而不是将其完全存储在内存中。可以参考微软官方文档中提供的方法(链接为http://msdn.microsoft.com/en-us/library/hh285054%28v=vs.110%29.aspx)。
在.NET中,数组大小有限制。但是在.NET 4.5中,可以通过特殊的配置选项打开对大数组(大于2GB)的支持(链接为http://msdn.microsoft.com/en-us/library/hh285054.aspx)。
如果只想读取文件的前x个字节(例如10个字节),那么读取全部字节的方法并不是最佳解决方案。
为了支持大对象,需要确保将解决方案的Web项目和IIS网站都设置为64位运行。
对于大文件的读取,上述方法不应该被接受或评为最佳答案。代码中给出的语句"你不应该一次性将整个文件读取到内存中,而应该分块读取"是正确的,但没有提供相应的代码。直到这部分得到解决之前,我会给予负面评价,因为这个答案的代码非常误导人,并与那个非常正确的语句相矛盾。
关于文件的编码问题,没有提供具体解决方法。