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
可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
回答1:
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();
}
}
回答2:
You need to make your own Stream class that validates its position and returns the desired subset.
I'm not aware of any built-in classes that do this.
回答3:
What exactly are you scared of duplicating? I doubt you have anything super performance critical, parse your Stream on the fly and use a MemoryStream till you find you need something else.
回答4:
Looks like StreamMuxer project was created with similar purpose in mind.