如何在没有缓冲区的情况下同时将.NET Stream写入另外两个Streams?

时间:2009-02-26 19:33:27

标签: .net multithreading streaming

在我之前的问题中,有人评论说可以同时将.NET Stream写入另外两个Streams。我只能找到一种方法,但使用临时变量(缓冲区)来存储输入流的内容(完全或部分一次)。

  1. 如果不使用缓冲区,有什么方法可以做到这一点吗?
  2. 有什么方法可以同时进行吗?

2 个答案:

答案 0 :(得分:5)

使用缓冲区可以异步写入两个流,假设流支持正确的异步访问。这实际上是并发的 - 虽然你有一个棘手的工作,保持所有的缓冲区同步,因为你可以在另一个缓冲区完成之前很长一段时间内完成第一个缓冲区的写入。

据我所知,没有使用至少一个字节的缓冲区就无法从一个(一般)流复制到另一个流。 (当然,只使用一个字节就会非常低效。)

答案 1 :(得分:4)

如果您乐意将并发性限制为最慢流的速率,那么这非常简单并且不需要额外的缓冲区,我已经从内存中写了它,所以可能会把它弄乱一点。

此外,它没有实现所需的所有覆盖,CanRead,CanSeek之类的东西都是为了简单起见而被删除,只是完成了核心并发写作。

using System;
using System.IO;
using System.Threading;

namespace MultiCastStream
{   
  public class MultiWriteStream : Stream
  {
    private readonly Stream[] streams;      
    private AutoResetEvent[] waits;
    private readonly IAsyncResult[] results;

    public MultiWriteStream(params Stream[] streams)
    {
      this.streams = (Stream[])streams.Clone();
      this.results = new IAsyncResult[this.streams.Length];
    }

    private void prepWaits()
    {
      if (waits == null)
      {
        this.waits = new AutoResetEvent[this.streams.Length];
        for(int i= 0; i < this.waits.Length; i++)
        {
          this.waits[i] = new AutoResetEvent(false);
        }
      }
      else
      {
        for(int i= 0; i < this.waits.Length; i++)
        {
          this.waits[i].Reset();
        }
      }
    }

    public override void Write (byte[] buffer, int offset, int count)
    {
      prepWaits();
      for( int i = 0; i < this.streams.Length; i++)
      {
        this.results[i] = streams[i].BeginWrite(
          buffer, offset, count, this.Release, waits[i]);   
      }
      WaitHandle.WaitAll(waits);
      for( int i = 0; i < this.streams.Length; i++)
      {
        this.results[i] = this.streams[i].EndWrite(results[i]); 
      }
    }

    private void Release(IAsyncResult result)
    {
      ((AutoResetEvent)result.AsyncState).Set();
    }

    public override void WriteByte (byte value)
    {
      // no point doing this asynchronously
      foreach (Stream s in this.streams) 
      s.WriteByte (value);
    }

    protected override void Dispose (bool disposing)
    {
      base.Dispose (disposing);
      if (this.waits != null)
      {
        foreach (AutoResetEvent w in this.waits)
          w.Close();
      }
      foreach (Stream s in this.streams)
        s.Dispose();
    }       
  }
}