最好的方式来阅读大量文件成一个字节列在C#?
-
19-09-2019 - |
题
我有一个网络服务器将宣读大二进制文件(几兆)字节到阵列。服务器可读的几个文件在同一时间(不同页的请求),所以我在寻找最优化的方式为这样做并没有征税的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(或阅读器/迭代器的一些变体)。也就是说尤其重要当有多个并行操作(如由问题的建议),以尽量减少系统负载和最大化吞吐量。
例如,如果流数据到呼叫者:
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是一个缓冲区的大小。
我也建议阅读有关的FileStream 和 BufferedStream 。
作为总是一个简单的示例程序来分析这是最快的将是最有利的。
此外,您的底层硬件会对性能产生很大的影响。您正在使用基于服务器的硬盘驱动器的大容量高速缓存和板载内存缓存RAID卡?或者,您使用连接到IDE接口标准驱动?
根据操作的频率,该文件的大小,以及你正在寻找的文件数,还有其他性能问题要考虑。有一点要记住,就是每个字节数组将在垃圾收集器的怜悯被释放。如果你不缓存任何数据,你可能最终会产生大量的垃圾,并失去大部分的性能来的在GC %的时间。如果块大于85K时,你会被分配到大对象堆(LOH),这将要求所有世代的收集以释放(这是非常昂贵的,并且在服务器上,而它的事情将停止所有执行)。此外,如果你有一吨的LOH的对象,你可以用LOH碎片(蕙是从来没有压缩),这会导致性能低下和内存不足异常结束。您可以回收的过程中,一旦你打的某一点,但我不知道这是一个最好的做法。
的一点是,你之前不一定只是在读取所有字节到内存中以最快的方式可能的,或者您可能对交易总体表现短期的表现应该考虑你的应用程序的整个生命周期。
我说BinaryReader
是好的,但可以进行重构此,而不是代码的所有的那些行的用于获取缓冲器的长度:
public byte[] FileToByteArray(string fileName)
{
byte[] fileData = null;
using (FileStream fs = File.OpenRead(fileName))
{
using (BinaryReader binaryReader = new BinaryReader(fs))
{
fileData = binaryReader.ReadBytes((int)fs.Length);
}
}
return fileData;
}
应该比使用.ReadAllBytes()
好,因为我在包括.ReadAllBytes()
的评论者之一曾与文件> 600 MB的问题,因为BinaryReader
是为这样的事情上响应的评论看到。另外,把它在一个using
语句确保FileStream
和BinaryReader
闭合且布置。
在的情况下用“一个大文件”是指超过4GB的限制,那么我的以下书面代码逻辑是适当的。关键问题要注意的是与Seek方法使用的LONG数据类型。作为长是能够指向超过2 ^ 32个数据的边界。 在这个例子中,代码被处理第一处理在1GB的块大文件,大的整个1GB块被处理后,则遗留(<1GB)字节进行处理。我用这个代码计算超过4GB大小的文件的CRC。 (使用 https://crc32c.machinezoo.com/ 以在该示例中,计算CRC32C)
private uint Crc32CAlgorithmBigCrc(string fileName)
{
uint hash = 0;
byte[] buffer = null;
FileInfo fileInfo = new FileInfo(fileName);
long fileLength = fileInfo.Length;
int blockSize = 1024000000;
decimal div = fileLength / blockSize;
int blocks = (int)Math.Floor(div);
int restBytes = (int)(fileLength - (blocks * blockSize));
long offsetFile = 0;
uint interHash = 0;
Crc32CAlgorithm Crc32CAlgorithm = new Crc32CAlgorithm();
bool firstBlock = true;
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
buffer = new byte[blockSize];
using (BinaryReader br = new BinaryReader(fs))
{
while (blocks > 0)
{
blocks -= 1;
fs.Seek(offsetFile, SeekOrigin.Begin);
buffer = br.ReadBytes(blockSize);
if (firstBlock)
{
firstBlock = false;
interHash = Crc32CAlgorithm.Compute(buffer);
hash = interHash;
}
else
{
hash = Crc32CAlgorithm.Append(interHash, buffer);
}
offsetFile += blockSize;
}
if (restBytes > 0)
{
Array.Resize(ref buffer, restBytes);
fs.Seek(offsetFile, SeekOrigin.Begin);
buffer = br.ReadBytes(restBytes);
hash = Crc32CAlgorithm.Append(interHash, buffer);
}
buffer = null;
}
}
//MessageBox.Show(hash.ToString());
//MessageBox.Show(hash.ToString("X"));
return hash;
}
使用C#中的BufferedStream类以提高性能。缓冲区是用于高速缓存数据,从而减少了呼叫的操作系统的数目在存储器的字节的块。缓冲器来提高读取和写入性能。
请参阅有关代码示例和附加说明以下内容: http://msdn.microsoft.com/en-us/库/ system.io.bufferedstream.aspx
使用这样的:
bytesRead = responseStream.ReadAsync(buffer, 0, Length).Result;
我会建议您尝试的Response.TransferFile()
方法则Response.Flush()
和Response.End()
为您提供服务大文件。
如果你处理上述文件2GB,你会发现,上述方法失败。
这是很容易的只是手流掉 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;
}
}