传递流的子序列而不将其内容复制到新实例中

Passing subsequence of a stream without copying its content into a new instance

假设我有以下方法:

void Upload(Stream stream)
{
    // uploads the content of the specified stream somewhere
}

让我们进一步假设我得到了一些二进制文件 f,其中包含一些我想使用上述方法上传的数据。 但是:我要上传的不是整个文件。只是f的一部分。更准确地说,所需数据从某个位置 s >= 0 开始并在某个位置 e <= f.Length 结束。

有没有办法传递一个 Stream 实例,它从位置 s 开始,长度为 e,而不复制 ss 之间的所有字节e 到一个新的流实例?我问是因为有可能文件 f 很大,我不想对可能可用的 RAM 做出假设。

请考虑使用 Stream.CanSeek Property, Stream.Position Property, Stream.Seek Method 到 "access" 流的特定部分。

要有一个单独的 Stream 具有适当长度的实例,似乎需要实现一个 SubStream class — 代表子流的包装器。以下参考资料可用于实现此类包装器:

  1. How to access part of a FileStream or MemoryStream, Social MSDN.
  2. How to expose a sub section of my stream to a user, Whosebug.

如果在调用该方法之前修改原始流中的指针可行,则使用Seek to set the starting position and SetLength设置结束位置。然后,您可以将流传递给该方法,它应该只触及该部分(假设它没有在内部寻求回到开头)。

不幸的是,SetLength 会截断流,因此如果出于某种原因需要,您以后将无法访问其余部分。但是,如果这不是必需的,这应该可行。

编辑:由于您需要保留原始流,这些是我能想到的其他选项:

  • 如果您有权访问该路径(并且它未被其他流锁定),您可以打开一个新的文件流并发送该流的截断版本。
  • 您可以将需要的部分复制到新的流中,例如 MemoryStream。您不需要复制整个文件,但需要使用 Seek and Read.

    复制要上传的部分
    byte[] data = new byte[size];
    stream.Seek(position, SeekOrigin.Begin);
    stream.Read(data, 0, size);
    using (MemoryStream subStream = new MemoryStream(data))
    {
        Upload(subStream);
    }
    
  • 您可以编写自己的流实现来执行您想要的操作,仅访问另一个流的特定部分。