C# 如何将写入流1的内容通过管道传输到流2?
这是我的设想:C# 如何将写入流1的内容通过管道传输到流2?,c#,.net,stream,C#,.net,Stream,这是我的设想: producer.WriteStream(stream); consumer.ReadStream(stream); 我想要一种允许生产者生成的字节逐步传输到消费者的东西 我可以将所有内容写入内存流,然后倒带并在消费者上读取,但这会导致巨大的内存消耗 如何实现这一点?使用管道作为数据的底层传输,您可以有一个“写入流”(服务器)和一个“读取流”(客户端),允许这种通信机制 无论是匿名管道还是命名管道(如果需要进程间通信),操作都非常简单。要在管道流中创建管道,请执行以下操作: A
producer.WriteStream(stream);
consumer.ReadStream(stream);
我想要一种允许生产者
生成的字节逐步传输到消费者
的东西
我可以将所有内容写入内存流
,然后倒带并在消费者
上读取,但这会导致巨大的内存消耗
如何实现这一点?使用管道作为数据的底层传输,您可以有一个“写入流”(服务器)和一个“读取流”(客户端),允许这种通信机制 无论是匿名管道还是命名管道(如果需要进程间通信),操作都非常简单。要在管道流中创建管道,请执行以下操作:
AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream();
AnonymousPipeClientStream pipeClient =
new AnonymousPipeClientStream(pipeServer.GetClientHandleAsString());
现在,您可以将其用作写入和读取:
producer.WriteStream(pipeServer);
// somewhere else...
consumer.ReadStream(pipeClient);
我只是为了好玩而把它放在一起,它没有经过测试,可能有一些bug。您只需将
ReaderStream
传递给读卡器,将WriterStream
传递给编写器
public class LoopbackStream
{
public Stream ReaderStream { get; }
public Stream WriterStream { get;}
private readonly BlockingCollection<byte[]> _buffer;
public LoopbackStream()
{
_buffer = new BlockingCollection<byte[]>();
ReaderStream = new ReaderStreamInternal(_buffer);
WriterStream = new WriterStreamInternal(_buffer);
}
private class WriterStreamInternal : Stream
{
private readonly BlockingCollection<byte[]> _buffer;
public WriterStreamInternal(BlockingCollection<byte[]> buffer)
{
_buffer = buffer;
CanRead = false;
CanWrite = false;
CanSeek = false;
}
public override void Close()
{
_buffer.CompleteAdding();
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
var newData = new byte[count];
Array.Copy(buffer, offset, newData, 0, count);
_buffer.Add(newData);
}
public override void Flush()
{
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override bool CanRead { get; }
public override bool CanSeek { get; }
public override bool CanWrite { get; }
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
}
private class ReaderStreamInternal : Stream
{
private readonly BlockingCollection<byte[]> _buffer;
private readonly IEnumerator<byte[]> _readerEnumerator;
private byte[] _currentBuffer;
private int _currentBufferIndex = 0;
public ReaderStreamInternal(BlockingCollection<byte[]> buffer)
{
_buffer = buffer;
CanRead = true;
CanWrite = false;
CanSeek = false;
_readerEnumerator = _buffer.GetConsumingEnumerable().GetEnumerator();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_readerEnumerator.Dispose();
}
base.Dispose(disposing);
}
public override int Read(byte[] buffer, int offset, int count)
{
if (_currentBuffer == null)
{
bool read = _readerEnumerator.MoveNext();
if (!read)
return 0;
_currentBuffer = _readerEnumerator.Current;
}
var remainingBytes = _currentBuffer.Length - _currentBufferIndex;
var readBytes = Math.Min(remainingBytes, count);
Array.Copy(_currentBuffer, _currentBufferIndex, buffer, offset, readBytes);
_currentBufferIndex += readBytes;
if (_currentBufferIndex == _currentBuffer.Length)
_currentBuffer = null;
return readBytes;
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override void Flush()
{
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override bool CanRead { get; }
public override bool CanSeek { get; }
public override bool CanWrite { get; }
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
}
}
公共类LoopbackStream
{
公共流读取器流{get;}
公共流写入器流{get;}
私有只读阻止收集\u缓冲区;
公共环后流()
{
_缓冲区=新的BlockingCollection();
ReaderStream=新的ReaderStreamInternal(_缓冲区);
WriterStream=新的WriterStreamInternal(\u缓冲区);
}
私有类WriterStreamInternal:流
{
私有只读阻止收集\u缓冲区;
public WriterStreamInternal(阻止收集缓冲区)
{
_缓冲区=缓冲区;
CanRead=false;
CanWrite=false;
CanSeek=false;
}
公共覆盖无效关闭()
{
_buffer.CompleteAdding();
}
公共重写整型读取(字节[]缓冲区、整型偏移量、整型计数)
{
抛出新的NotSupportedException();
}
公共重写无效写入(字节[]缓冲区、整数偏移量、整数计数)
{
var newData=新字节[计数];
复制(缓冲区、偏移量、newData、0、计数);
_buffer.Add(newData);
}
公共覆盖无效刷新()
{
}
公共覆盖长寻道(长偏移,参见原始坐标系)
{
抛出新的NotSupportedException();
}
公共覆盖无效设置长度(长值)
{
抛出新的NotSupportedException();
}
公共覆盖布尔可以读取{get;}
公共覆盖布尔CanSeek{get;}
公共覆盖布尔可以写入{get;}
公共覆盖长长度
{
获取{抛出新的NotSupportedException();}
}
公众优先多头仓位
{
获取{抛出新的NotSupportedException();}
设置{抛出新的NotSupportedException();}
}
}
私有类ReaderStreamInternal:流
{
私有只读阻止收集\u缓冲区;
专用只读IEnumerator\u Readernumerator;
专用字节[]_currentBuffer;
私有int_currentBufferIndex=0;
公共ReaderStreamInternal(阻止收集缓冲区)
{
_缓冲区=缓冲区;
CanRead=true;
CanWrite=false;
CanSeek=false;
_readerEnumerator=_buffer.GetConsumingEnumerable().GetEnumerator();
}
受保护的覆盖无效处置(布尔处置)
{
如果(处置)
{
_readerEnumerator.Dispose();
}
基地。处置(处置);
}
公共重写整型读取(字节[]缓冲区、整型偏移量、整型计数)
{
如果(_currentBuffer==null)
{
bool read=_readernumerator.MoveNext();
如果(!读取)
返回0;
_currentBuffer=\u readernumerator.Current;
}
var remainingBytes=\u currentBuffer.Length-\u currentBufferIndex;
var readBytes=Math.Min(剩余字节数,计数);
复制(_currentBuffer,_currentBufferIndex,buffer,offset,readBytes);
_currentBufferIndex+=readBytes;
如果(_currentBufferIndex==_currentBuffer.Length)
_currentBuffer=null;
返回readBytes;
}
公共重写无效写入(字节[]缓冲区、整数偏移量、整数计数)
{
抛出新的NotSupportedException();
}
公共覆盖无效刷新()
{
}
公共覆盖长寻道(长偏移,参见原始坐标系)
{
抛出新的NotSupportedException();
}
公共覆盖无效设置长度(长值)
{
抛出新的NotSupportedException();
}
公共覆盖布尔可以读取{get;}
公共覆盖布尔CanSeek{get;}
公共覆盖布尔可以写入{get;}
公共覆盖长长度
{
获取{抛出新的NotSupportedException();}
}
公众优先多头仓位
{
获取{抛出新的NotSupportedException();}
设置{抛出新的NotSupportedException();}
}
}
}
使用两个实例,一个用于读取(客户端),一个用于写入(服务器)。谢谢@Amit,您能详细说明如何将这些流“绑定”在一起吗。。我不清楚。如果您需要将数据从一个流传输到另一个流,您通常通过从源读取块(例如1K或4K)并将其放入目标,直到源流为空。这比我的解决方案简单得多。