2009-06-28 11 views
6

誰でもストリームスプリッタの実装がどこにあるのか知っていますか?.NETでStreamを分割(コピー)するにはどうすればよいですか?

私はストリームを取ってお互いに影響を与えずに独立して読みとり、閉じることができる2つの別々のストリームを取得しようとしています。これらのストリームはそれぞれ元のストリームと同じバイナリデータを返す必要があります。ポジションやシークなどを実装する必要はありません...転送のみ。

ストリーム全体をメモリにコピーして複数回配信するだけでなく、自分自身を実装するにはかなりシンプルであれば好きです。

これを行うことができるものはありますか?

+1

何か... –

+0

は、それはおそらく循環バッファをベースにする必要があります。私は時間があれば簡単な実装を書くつもりです。 – Noldorin

答えて

4

出荷時の状態ではありません。

元のストリームのデータをFIFO形式でバッファリングし、すべての "リーダー"ストリームで読み取られたデータのみを破棄する必要があります。

私が使用したい:「

  • 一部を、必要に応じて

    • A「管理」オブジェクトがソースストリームから追加データをバッファリングするためのチャンクを保持し、読み[]バイトのキューのいくつかの並べ替えを保持しますどのバッファがどこにあるかを知っていて、「管理」から次のチャンクを要求し、チャンクを使用しないときに通知してキューから取り除くことができる「読者」インスタンス
  • 1

    私はあなたがそのための汎用的な実装。ストリームはかなり抽象的で、バイトがどこから来ているのか分かりません。たとえば、シークをサポートするかどうかは分かりません。あなたは操作の相対的なコストを知らない。 (ストリームは、リモートサーバーからデータを読み取る抽象化でも、バックアップテープからでも読み取ることができます)。

    MemoryStreamを使用してコンテンツを一度格納できる場合は、同じバッファを使用して2つの別々のストリームを作成できます。それらは独立したストリームとして動作しますが、メモリは一度しか使用しません。

    それ以外の場合は、1つのストリームから読み取られたバイトを格納するラッパークラスを作成し、2番目のストリームでも読み取られるまでは最適な方法だと思います。それは、あなたが望む転送のみの動作を与えますが、最悪の場合、最初のStreamがすべてのコンテンツの読み込みを完了するまで、2番目のStreamが読み込まれないと、すべてのバイトをメモリに格納する危険性があります。

    +0

    このアプリケーションの用途は何ですか? – headsling

    1

    これは、ソースストリームの少なくとも一部を複製することなく、実際には実行できません。ほとんどの場合、消費されたレート(複数のスレッド?)を制御できるかのように聞こえません。あなたは、他の人の読書に関する賢明な何かをすることができます(そしてその時点でコピーを作成します)が、この複雑さは問題の価値がないように聞こえます。

    +0

    マルチスレッドのシナリオで使用される場合、OS /プラットフォームが同じファイルの複数の読者を持つための独自の固有のメカニズムを使用しないようにします。 メモリ内で使用されている場合は、最悪の場合は常にストリーム全体をコピーしなければならない可能性がありますので、このようなことを試してみると多分努力しています...複数の消費者モデルへのプッシュはおそらくもっと役に立ちます – ShuggyCoUk

    3

    メモリにすべてのデータをバッファする(ストリームがそれぞれBOFとEOFの場合)危険にさらされることがあります。

    私は、ディスクにストリームを書くことが容易ではないだろうか、それをコピーして、Close()に内蔵された自己削除(すなわちFileStreamの周りに独自のStreamラッパーを記述)で、ディスクからの読み取り2つのストリームを持っています。

    0

    経由で見つかったいくつかのコンテキスト

    を提供する必要がありますあなたの読書作業の1つを除くすべてが非同期であるため、単一のOSスレッドだけを使用して同じデータを2回処理できるはずです。

    あなたが望むと思うのは、これまでに見たデータブロックのリンクリストです。次に、このリストへのポインタを保持する複数のカスタムストリームインスタンスを持つことができます。ブロックがリストの最後にくると、それらはガベージコレクションされます。メモリをすぐに再利用するには、他の種類の循環リストと参照カウントが必要です。実行可能ですが、より複雑です。

    カスタムストリームがキャッシュからReadAsync呼び出しに応答できる場合は、データをコピーし、ポインタをリストの下に進めて戻ります。

    ストリームがキャッシュリストの最後に追いついたとき、待機していないストリームに1つのReadAsyncを発行し、返されたTaskをデータブロックでキャッシュします。したがって、他のStreamリーダーもこの読み込みが完了する前に読み込みを試み、同じTaskオブジェクトを返すことができます。

    このようにして、両方の読者は、同じReadAsync呼び出しの結果に待っています。単一の読み取りが戻ると、両方の読み取りタスクは、その処理の次のステップを順次実行します。

    0

    私はgithubとNuGetでSplitStreamを利用できるようにしました。

    このようになります。

    using (var inputSplitStream = new ReadableSplitStream(inputSourceStream)) 
    
    using (var inputFileStream = inputSplitStream.GetForwardReadOnlyStream()) 
    using (var outputFileStream = File.OpenWrite("MyFileOnAnyFilestore.bin")) 
    
    using (var inputSha1Stream = inputSplitStream.GetForwardReadOnlyStream()) 
    using (var outputSha1Stream = SHA1.Create()) 
    { 
        inputSplitStream.StartReadAhead(); 
    
        Parallel.Invoke(
         () => { 
          var bytes = outputSha1Stream.ComputeHash(inputSha1Stream); 
          var checksumSha1 = string.Join("", bytes.Select(x => x.ToString("x"))); 
         }, 
         () => { 
          inputFileStream.CopyTo(outputFileStream); 
         }, 
        ); 
    } 
    

    非常に大きなストリームではテストしていませんが、試してみてください。

    githubの:UNIXでtee` `のようなhttps://github.com/microknights/SplitStream

    +0

    スタックオーバーフローでは実際のコードは役に立ちません。良いSO答えは、ここでのケースのように一部の外部リソースに完全に依存するのではなく、完全に自己完結型です。読者が回答の投稿自体から重要な情報をすべて入手できるように、回答を編集してください。 –

    関連する問題