2011-11-22 13 views
13

バイトデータをバッファの末尾に付加することができるクラスの.NETデータ構造/コンビネーションがありますが、最初からすべてのピークとリードが開始されます。私は読む?バイトストリームに特化したFIFO /キューバッファ

MemoryStreamクラスはこれに含まれているようですが、読み書きのために別々の場所を維持する必要があります。読み込み後に自動的にデータを破棄することはありません。

答えは普通のパイプのように、私がやろうとしているが、私は、私は、同じプロセスの異なるコンポーネントで上の非同期I/Oを行うことができます何かを好む基本的に何であるthis questionへの返信に掲載されていますまたはネットワークストリーム(私は最初にデータをフィルタリング/処理する必要があります)。

+1

読み取りバッファ内で前後にジャンプすると何か問題はありますか? – Ryan

+0

NetworkStreamスタイルの読み込み、読み込み、読み込みなどとは対照的に、私が言ったこととそれを追跡する必要があるだけです – Deanna

+0

異なるサイズの配列を読み書きする必要がありますか? 'byte []'の待ち行列があなたにとって十分なものではないでしょうか? – svick

答えて

10

私は、仕事場でプロジェクト用に書いたロジックのコピーを一度投稿します。このバージョンの利点は、バッファリングされたデータのリンクリストで動作するため、読み込み時に大量のメモリをキャッシュしたり、メモリをコピーしたりする必要がないことです。さらに、そのスレッドセーフであり、ネットワークストリームのように動作します。利用可能なデータがないときに読み込むとき:データが利用可能になるかタイムアウトになるまで待ちます。また、x個のバイトを読み込み、y個のバイトしかない場合は、すべてのバイトを読み込んだ後に戻ります。私はこれが助けて欲しい!

public class SlidingStream : Stream 
{ 
    #region Other stream member implementations 

    ... 

    #endregion Other stream member implementations 

    public SlidingStream() 
    { 
     ReadTimeout = -1; 
    } 

    private readonly object _writeSyncRoot = new object(); 
    private readonly object _readSyncRoot = new object(); 
    private readonly LinkedList<ArraySegment<byte>> _pendingSegments = new LinkedList<ArraySegment<byte>>(); 
    private readonly ManualResetEventSlim _dataAvailableResetEvent = new ManualResetEventSlim(); 

    public int ReadTimeout { get; set; } 

    public override int Read(byte[] buffer, int offset, int count) 
    { 
     if (_dataAvailableResetEvent.Wait(ReadTimeout)) 
      throw new TimeoutException("No data available"); 

     lock (_readSyncRoot) 
     { 
      int currentCount = 0; 
      int currentOffset = 0; 

      while (currentCount != count) 
      { 
       ArraySegment<byte> segment = _pendingSegments.First.Value; 
       _pendingSegments.RemoveFirst(); 

       int index = segment.Offset; 
       for (; index < segment.Count; index++) 
       { 
        if (currentOffset < offset) 
        { 
         currentOffset++; 
        } 
        else 
        { 
         buffer[currentCount] = segment.Array[index]; 
         currentCount++; 
        } 
       } 

       if (currentCount == count) 
       { 
        if (index < segment.Offset + segment.Count) 
        { 
         _pendingSegments.AddFirst(new ArraySegment<byte>(segment.Array, index, segment.Offset + segment.Count - index)); 
        } 
       } 

       if (_pendingSegments.Count == 0) 
       { 
        _dataAvailableResetEvent.Reset(); 

        return currentCount; 
       } 
      } 

      return currentCount; 
     } 
    } 

    public override void Write(byte[] buffer, int offset, int count) 
    { 
     lock (_writeSyncRoot) 
     { 
      byte[] copy = new byte[count]; 
      Array.Copy(buffer, offset, copy, 0, count); 

      _pendingSegments.AddLast(new ArraySegment<byte>(copy)); 

      _dataAvailableResetEvent.Set(); 
     } 
    } 
} 
+1

良い見え、私は同じ道を進んでいた。私は今夜​​それを試してみるよ。 – Deanna

+0

利用できないときにデータを読み込もうとするとクラッシュするようです。 – svick

+0

@svick - まさに正しい、ドラフト、引数の検証などはありません。その唯一の理由はmanualResetEventです。私はreadメソッドの開始時にそれを待っています。今修正されました。ヘッドアップありがとう – Polity

1

コードは、受け入れられた答えより簡単です。 forループを使用する必要はありません。:

/// <summary> 
/// This class is a very fast and threadsafe FIFO buffer 
/// </summary> 
public class FastFifo 
{ 
    private List<Byte> mi_FifoData = new List<Byte>(); 

    /// <summary> 
    /// Get the count of bytes in the Fifo buffer 
    /// </summary> 
    public int Count 
    { 
     get 
     { 
      lock (mi_FifoData) 
      { 
       return mi_FifoData.Count; 
      } 
     } 
    } 

    /// <summary> 
    /// Clears the Fifo buffer 
    /// </summary> 
    public void Clear() 
    { 
     lock (mi_FifoData) 
     { 
      mi_FifoData.Clear(); 
     } 
    } 

    /// <summary> 
    /// Append data to the end of the fifo 
    /// </summary> 
    public void Push(Byte[] u8_Data) 
    { 
     lock (mi_FifoData) 
     { 
      // Internally the .NET framework uses Array.Copy() which is extremely fast 
      mi_FifoData.AddRange(u8_Data); 
     } 
    } 

    /// <summary> 
    /// Get data from the beginning of the fifo. 
    /// returns null if s32_Count bytes are not yet available. 
    /// </summary> 
    public Byte[] Pop(int s32_Count) 
    { 
     lock (mi_FifoData) 
     { 
      if (mi_FifoData.Count < s32_Count) 
       return null; 

      // Internally the .NET framework uses Array.Copy() which is extremely fast 
      Byte[] u8_PopData = new Byte[s32_Count]; 
      mi_FifoData.CopyTo(0, u8_PopData, 0, s32_Count); 
      mi_FifoData.RemoveRange(0, s32_Count); 
      return u8_PopData; 
     } 
    } 

    /// <summary> 
    /// Gets a byte without removing it from the Fifo buffer 
    /// returns -1 if the index is invalid 
    /// </summary> 
    public int PeekAt(int s32_Index) 
    { 
     lock (mi_FifoData) 
     { 
      if (s32_Index < 0 || s32_Index >= mi_FifoData.Count) 
       return -1; 

      return mi_FifoData[s32_Index]; 
     } 
    } 
} 
+0

これは本質的に非同期またはブロックの欲望を満たしていないリンクされた質問と同じです。しかし、ありがとう。 – Deanna

+0

OKですが、そのコードはそれほどエレガントではなく、スレッドセーフではありません。 16行を必要とするのではなく、6行で行うことができます。 – Elmue

関連する問題