首页 文章

如何通过块读取文件

提问于
浏览
0

我有点困惑,如果每个块都有自己的大小,我应该如何通过块读取大文件(> 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

所以在这种情况下,首先我需要做的是读取chunk的 Headers 并准确地了解什么是块大小 . 我只读取和写入文件字节数组 . 但我有一个问题 - 如何看待chunk的 Headers ?可能是 Headers 必须包含一些边界?

1 回答

  • 7

    如果文件是严格构造的,以便每个数据块前面都有一个32位长度值,那么它很容易阅读 . 每个块的“ Headers ”只是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.
    }
    

    请注意,您不需要提供自己的缓冲 .

相关问题