假设我想要将三个文件一起流式传输给一个用户,但是他没有给我一个Stream
对象来下推字节,而是我必须给他一个Stream
对象,让他从中提取字节。我想获取我的三个FileStream
对象(或者更聪明的是一个IEnumerable<Stream>
),并返回一个新的ConcatenatedStream
对象,该对象将按需从源流中拉出。
发布于 2010-10-07 14:33:29
class ConcatenatedStream : Stream
{
Queue<Stream> streams;
public ConcatenatedStream(IEnumerable<Stream> streams)
{
this.streams = new Queue<Stream>(streams);
}
public override bool CanRead
{
get { return true; }
}
public override int Read(byte[] buffer, int offset, int count)
{
int totalBytesRead = 0;
while (count > 0 && streams.Count > 0)
{
int bytesRead = streams.Peek().Read(buffer, offset, count);
if (bytesRead == 0)
{
streams.Dequeue().Dispose();
continue;
}
totalBytesRead += bytesRead;
offset += bytesRead;
count -= bytesRead;
}
return totalBytesRead;
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override void Flush()
{
throw new NotImplementedException();
}
public override long Length
{
get { throw new NotImplementedException(); }
}
public override long Position
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
}
发布于 2010-10-07 14:36:07
未经测试,但类似于:
class StreamEnumerator : Stream
{
private long position;
bool closeStreams;
IEnumerator<Stream> iterator;
Stream current;
private void EndOfStream() {
if (closeStreams && current != null)
{
current.Close();
current.Dispose();
}
current = null;
}
private Stream Current
{
get {
if(current != null) return current;
if (iterator == null) throw new ObjectDisposedException(GetType().Name);
if (iterator.MoveNext()) {
current = iterator.Current;
}
return current;
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
EndOfStream();
iterator.Dispose();
iterator = null;
current = null;
}
base.Dispose(disposing);
}
public StreamEnumerator(IEnumerable<Stream> source, bool closeStreams)
{
if (source == null) throw new ArgumentNullException("source");
iterator = source.GetEnumerator();
this.closeStreams = closeStreams;
}
public override bool CanRead { get { return true; } }
public override bool CanWrite { get { return false; } }
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override void WriteByte(byte value)
{
throw new NotSupportedException();
}
public override bool CanSeek { get { return false; } }
public override bool CanTimeout { get { return false; } }
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void Flush()
{ /* nothing to do */ }
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get { return position; }
set { if (value != this.position) throw new NotSupportedException(); }
}
public override int Read(byte[] buffer, int offset, int count)
{
int result = 0;
while (count > 0)
{
Stream stream = Current;
if (stream == null) break;
int thisCount = stream.Read(buffer, offset, count);
result += thisCount;
count -= thisCount;
offset += thisCount;
if (thisCount == 0) EndOfStream();
}
position += result;
return result;
}
}
发布于 2017-11-16 04:28:05
这里有一个支持搜索的选项,这在许多情况下都是必要的。它缺少一些处理底层流的功能,如果您愿意假设底层流不会改变长度,那么它可能会更高效一些。然后可以一次计算总长度和流偏移量。
public sealed class ConcatenatedStream : Stream
{
List<Stream> streams;
private long _Position { get; set; }
public ConcatenatedStream(List<Stream> streams)
{
this.streams = streams;
Seek(0, SeekOrigin.Begin);
}
public override bool CanRead
{
get { return true; }
}
public override int Read(byte[] buffer, int offset, int count)
{
if (streams.Count == 0)
return 0;
var startStream = 0;
var cumulativeCapacity = 0L;
for (var i = 0; i < streams.Count; i++)
{
cumulativeCapacity += streams[i].Length;
if (_Position < cumulativeCapacity)
{
startStream = i;
break;
}
}
var bytesRead = 0;
var curStream = startStream;
while (_Position < Length && bytesRead < count && curStream < streams.Count)
{
var r = streams[curStream].Read(buffer, offset + bytesRead, count - bytesRead);
bytesRead += r;
Seek(_Position + r, SeekOrigin.Begin);
curStream++;
}
return bytesRead;
}
public override bool CanSeek
{
get { return true; }
}
public override bool CanWrite
{
get { return false; }
}
public override void Flush()
{
throw new NotImplementedException();
}
public override long Length
{
get {
long length = 0;
for (var i = 0; i < streams.Count; i++)
{
length += streams[i].Length;
}
return length;
}
}
public override long Position
{
get
{
return _Position;
}
set
{
Seek(value, SeekOrigin.Begin);
}
}
public override long Seek(long offset, SeekOrigin origin)
{
if (origin == SeekOrigin.Begin)
{
_Position = offset;
var prevLength = 0L;
var cumulativeLength = 0L;
for (var i = 0; i < streams.Count; i++)
{
cumulativeLength += streams[i].Length;
if (offset < cumulativeLength)
{
streams[i].Seek(offset - prevLength, SeekOrigin.Begin);
return _Position;
}
prevLength = cumulativeLength;
}
}
if (origin == SeekOrigin.Current)
{
var newAbs = _Position + offset;
return Seek(newAbs, SeekOrigin.Begin);
}
else if(origin == SeekOrigin.End)
{
var newAbs = Length - offset;
return Seek(newAbs, SeekOrigin.Begin);
}
throw new NotImplementedException();
}
public override void SetLength(long value)
{
throw new NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
}
https://stackoverflow.com/questions/3879152
复制相似问题