MemoryMappedViewStream.ReadAsync() 读取超出内存映射文件末尾的内容

问题描述 投票:0回答:1

我正在研究一个示例,以展示如何读取大文件并分块处理它。然而,它似乎行为不当,返回了无效的读取字节数。

例如,假设我们有一个长度为 8320 字节的测试文件,我们使用以下代码以 4096 字节的块读取它:

public static async IAsyncEnumerable<byte[]> ConvertInChunks(string filePath, int chunkSize,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
    byte[]? buffer = null;
    try
    {
        buffer = ArrayPool<byte>.Shared.Rent(chunkSize);
        var memory = buffer.AsMemory(0, chunkSize);

        var fileLength = new FileInfo(filePath).Length;
        using var mm = MemoryMappedFile.CreateFromFile(filePath);
        await using var accessor = mm.CreateViewStream();

        var bytesRead = 0L;
        while (bytesRead < fileLength)
        {
            var read = await accessor.ReadAsync(memory, cancellationToken);
            bytesRead += read;

            yield return memory[..read].ToArray();
        }
    }
    finally
    {
        if (buffer is not null)
            ArrayPool<byte>.Shared.Return(buffer);
    }
}

我发现最终迭代仍然返回

read
值 4096。这对我来说似乎是一个错误,但也许我在设置中做错了一些事情。我可以通过显式分割内存缓冲区来解决这个问题,使其成为剩余字节和 4096 之间的最小值,但我确实希望在流中剩余数据较少时调用 ReadAsync 读取 4096 或更少。请注意,我还尝试了另一个带有缓冲区和显式偏移量和计数的
ReadAsync
重载,它具有相同的行为。

c# async-await memory-mapped-files
1个回答
0
投票

此答案全部归功于@MarkGravell:

解决方案很简单,在创建调用中显式设置视图流大小:

var fileLength = new FileInfo(filePath).Length;
using var mm = MemoryMappedFile.CreateFromFile(filePath);
await using var accessor = mm.CreateViewStream(0, fileLength);
© www.soinside.com 2019 - 2024. All rights reserved.