2 Stimmen

Wie schreibt man einen .NET Stream in zwei andere Streams gleichzeitig ohne Puffer?

In meiner vorherigen Frage hat jemand angemerkt, dass es möglich ist, einen .NET Stream in zwei andere Streams gleichzeitig zu schreiben. Ich konnte nur einen Weg finden, aber mit einer temporären Variablen (Puffer), die den Inhalt (vollständig oder teilweise auf einmal) der Eingabe Stream speichern würde.

  1. Gibt es eine Möglichkeit, dies zu tun, ohne Puffer zu verwenden?
  2. Gibt es eine Möglichkeit, dies gleichzeitig zu tun?

5voto

Jon Skeet Punkte 1325502

Mit einem Puffer können Sie asynchron in beide Ströme schreiben, vorausgesetzt, die Ströme unterstützen einen ordnungsgemäßen asynchronen Zugriff. Das ist effektiv gleichzeitig - obwohl Sie eine schwierige Aufgabe haben, alle Puffer synchron zu halten, da einer den ersten Puffer lange vor dem anderen fertig schreiben könnte.

Soweit ich weiß, gibt es keine Möglichkeit, von einem (allgemeinen) Stream in einen anderen zu kopieren, ohne einen Puffer von mindestens einem Byte zu verwenden. (Und die Verwendung von nur einem einzigen Byte wird natürlich schmerzhaft ineffizient sein).

4voto

ShuggyCoUk Punkte 35230

Wenn Sie glücklich sind, Ihre Gleichzeitigkeit auf die Rate des langsamsten Stroms zu begrenzen, dann ist dies ziemlich einfach und erfordert keinen zusätzlichen Puffer, ich habe es aus dem Gedächtnis geschrieben, so könnte es ein wenig durcheinander gebracht haben.

Außerdem implementiert es nicht alle erforderlichen Überschreibungen, Dinge wie CanRead, CanSeek und dergleichen werden der Einfachheit halber übersprungen, nur der Kern des gleichzeitigen Schreibens wird durchgeführt.

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();
    }       
  }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X