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)并将其放入目标,直到源流为空。这比我的解决方案简单得多。