繁体   English   中英

如何按块读取文件

[英]How to read file by chunks

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM