在存在异步写入时实现读取

时间:2017-07-25 18:17:21

标签: c# .net stream

我有一个可以同时读写的流。 MSDN文档说我应该只在到达流末尾时从Read(buffer, offset, count)方法返回零。

由于读取和写入是异步的,因此如果内部缓冲区为空,则读取需要等到另一次写入发生。

我正在努力解决写作方法如何表明所有内容都已被写入的问题。我能想到的最好的方法是Dispose()(或Close())方法表示写作结束,但感觉非常错误。

我的流类实现为:

public class ContinuousStream : Stream
{
    private readonly IProducerConsumerCollection<byte> _buffer;

    public ContinuousStream() => _buffer = new ConcurrentQueue<byte>();

    public override int Read(byte[] buffer, int offset, int count)
    {
        var maxByteCount = offset + count > buffer.Length ? buffer.Length : count;
        var actualBytesRead = 0;

        for (var i = offset; i < maxByteCount && _buffer.TryTake(out var b); i++)
        {
            buffer[i] = b;
            actualBytesRead++;
        }

        return actualBytesRead;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        var maxByteCount = offset + count > buffer.Length ? buffer.Length : count;
        for (var i = offset; i < maxByteCount; i++)
        {
            _buffer.TryAdd(buffer[i]);
        }
    }
}

澄清

读写同时发生。阅读不应该等到一切都被缓冲后再运行。我怎么能向这个流发出信号,说明将要发生的所有文字都发生了?

1 个答案:

答案 0 :(得分:0)

实际上,我不太明白为什么你需要流式传输,并且不能单独使用IProducerConsumerCollection 。其中许多参数毫无意义。只需使用TryTake&amp; TryAdd而不是Read&amp;写在第一位。

但您可以使用 AutoResetEvent

public class ContinuousStream : Stream
{
    private readonly AutoResetEvent _are = new AutoResetEvent(false);
    private readonly IProducerConsumerCollection<byte> _buffer = new ConcurrentQueue<byte>();

    public override int Read(byte[] buffer, int offset, int count)
    {
        _are.WaitOne();
        var maxByteCount = offset + count > buffer.Length ? buffer.Length : count;
        var actualBytesRead = 0;

        for (var i = offset; i < maxByteCount && _buffer.TryTake(out var b); i++)
        {
            buffer[i] = b;
            actualBytesRead++;
        }

        return actualBytesRead;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        var maxByteCount = offset + count > buffer.Length ? buffer.Length : count;
        for (var i = offset; i < maxByteCount; i++)
        {
            _buffer.TryAdd(buffer[i]);
            _are.Set();
        }
    }
}