【问题标题】:How to read file by chunks如何按块读取文件
【发布时间】:2016-02-15 11:10:03
【问题描述】:

我有点困惑,我应该如何按块读取大文件(> 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

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

【问题讨论】:

  • 被标记为重复 - 看看这个你应该能够得到答案的地方stackoverflow.com/questions/17612853/…
  • 但我必须使用BufferedStream。我不能使用StreamReader
  • 您意识到FileStream 已经缓冲了文件,所以使用BufferedStream 毫无意义?
  • BufferedStream(如FileStream)是Stream,而StreamReaderStream读取,所以如果你必须使用它就不会意味着你不能使用另一个。

标签: c# .net stream


【解决方案1】:

如果文件结构严格,每个数据块前面都有一个 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.
}

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

【讨论】:

  • 看起来像我需要的东西
  • 并像BitConverter.GetBytes(bytesLength)那样写标题?
  • @isxaker 是的,完全正确。如果 bytesLength 是 32 位 int,BitConverter.GetBytes(bytesLength) 当然会返回一个 4 字节数组。
猜你喜欢
  • 2012-03-24
  • 2011-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-19
  • 1970-01-01
相关资源
最近更新 更多