问题描述
我有一个包含许多数据的流.我只想在另一个流中公开该数据的一部分.我要提取的数据通常超过 100mb.由于我已经有了包含数据的流,因此将该数据复制到另一个流并返回它似乎是一种浪费.我正在寻找一种方法来引用第一个流中的数据,同时控制第二个流可以引用的数据量.这可能吗
I have a stream that contains many pieces of data. I want to expose just a piece of that data in another stream. The piece of data I want to extract can often be over 100mb. Since I already have stream with the data in it it seems like a waste to copy that data to another stream and return that. What im looking for is a way to reference the data in the first stream while controlling how much of it the second stream can reference. Is this possible
推荐答案
Mark Gravell 对此进行了很好的实施 在此处详细说明.贴在那里的代码是:
There is a good implementation of this by Mark Gravell detailed here. The code posted there is:
using System.IO; using System; static class Program { // shows that we can read a subset of an existing stream... static void Main() { byte[] buffer = new byte[255]; for (byte i = 0; i < 255; i++) { buffer[i] = i; } using(MemoryStream ms = new MemoryStream(buffer)) using (SubStream ss = new SubStream(ms, 10, 200)) { const int BUFFER_SIZE = 17; // why not... byte[] working = new byte[BUFFER_SIZE]; int read; while ((read = ss.Read(working, 0, BUFFER_SIZE)) > 0) { for (int i = 0; i < read; i++) { Console.WriteLine(working[i]); } } } } } class SubStream : Stream { private Stream baseStream; private readonly long length; private long position; public SubStream(Stream baseStream, long offset, long length) { if (baseStream == null) throw new ArgumentNullException("baseStream"); if (!baseStream.CanRead) throw new ArgumentException("can't read base stream"); if (offset < 0) throw new ArgumentOutOfRangeException("offset"); this.baseStream = baseStream; this.length = length; if (baseStream.CanSeek) { baseStream.Seek(offset, SeekOrigin.Current); } else { // read it manually... const int BUFFER_SIZE = 512; byte[] buffer = new byte[BUFFER_SIZE]; while (offset > 0) { int read = baseStream.Read(buffer, 0, offset < BUFFER_SIZE ? (int) offset : BUFFER_SIZE); offset -= read; } } } public override int Read(byte[] buffer, int offset, int count) { CheckDisposed(); long remaining = length - position; if (remaining <= 0) return 0; if (remaining < count) count = (int) remaining; int read = baseStream.Read(buffer, offset, count); position += read; return read; } private void CheckDisposed() { if (baseStream == null) throw new ObjectDisposedException(GetType().Name); } public override long Length { get { CheckDisposed(); return length; } } public override bool CanRead { get { CheckDisposed(); return true; } } public override bool CanWrite { get { CheckDisposed(); return false; } } public override bool CanSeek { get { CheckDisposed(); return false; } } public override long Position { get { CheckDisposed(); return position; } set { throw new NotSupportedException(); } } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Flush() { CheckDisposed(); baseStream.Flush(); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { if (baseStream != null) { try { baseStream.Dispose(); } catch { } baseStream = null; } } } public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } }