我有点困惑,如果每个块都有自己的大小,我应该如何按块读取大文件(> 8GB(。
如果我知道块大小,它看起来像下面的代码:
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, ProgramOptions.BufferSizeForChunkProcessing))
{
using (BufferedStream bs = new BufferedStream(fs, ProgramOptions.BufferSizeForChunkProcessing))
{
byte[] buffer = new byte[ProgramOptions.BufferSizeForChunkProcessing];
int byteRead;
while ((byteRead = bs.Read(buffer, 0, ProgramOptions.BufferSizeForChunkProcessing)) > 0)
{
byte[] originalBytes;
using (MemoryStream mStream = new MemoryStream())
{
mStream.Write(buffer, 0, byteRead);
originalBytes = mStream.ToArray();
}
}
}
}
但是想象一下,我已经逐个块读取大文件,每个块都进行了一些编码(该操作更改后的块大小(,并将所有处理的块写入另一个新文件。现在我需要做相反的操作。但我不知道确切的块大小。我有个主意。处理完每个块后,我必须在块字节之前写入新的块大小。喜欢这个:
Number of block bytes
Block bytes
Number of block bytes
Block bytes
因此,在这种情况下,首先我需要做的是读取块的标头并了解块大小的确切含义。我只读取和写入文件字节数组。但我有一个问题 - 应该如何看待块的标题?可能标题必须包含一些边界?
如果文件结构严格,使得每个数据块前面都有一个 32 位长度值,那么它很容易读取。每个块的"标头"只是 32 位长度值。
如果要读取这样的文件,最简单的方法可能是将读取封装到返回IEnumerable<byte[]>
的方法中,如下所示:
public static IEnumerable<byte[]> ReadChunks(string path)
{
var lengthBytes = new byte[sizeof(int)];
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
int n = fs.Read(lengthBytes, 0, sizeof (int)); // Read block size.
if (n == 0) // End of file.
yield break;
if (n != sizeof(int))
throw new InvalidOperationException("Invalid header");
int blockLength = BitConverter.ToInt32(lengthBytes, 0);
var buffer = new byte[blockLength];
n = fs.Read(buffer, 0, blockLength);
if (n != blockLength)
throw new InvalidOperationException("Missing data");
yield return buffer;
}
}
然后你可以简单地使用它:
foreach (var block in ReadChunks("MyFileName"))
{
// Process block.
}
请注意,您不需要提供自己的缓冲。
试试这个
public static IEnumerable<byte[]> ReadChunks(string fileName)
{
const int MAX_BUFFER = 1048576;// 1MB
byte[] filechunk = new byte[MAX_BUFFER];
int numBytes;
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
long remainBytes = fs.Length;
int bufferBytes = MAX_BUFFER;
while (true)
{
if (remainBytes <= MAX_BUFFER)
{
filechunk = new byte[remainBytes];
bufferBytes = (int)remainBytes;
}
if ((numBytes = fs.Read(filechunk, 0, bufferBytes)) > 0)
{
remainBytes -= bufferBytes;
yield return filechunk;
}
else
{
break;
}
}
}
}