2009-02-10 76 views
5

我有一個文件列表,我需要按給定大小的byte []按特定順序讀取它們。這對於單個文件本身並不是問題,簡單的而((got = fs.Read(piece,0,pieceLength))> 0)完成工作完全正常。該文件的最後一部分可能比預期的要小,這很好。是否有內置的方式來處理多個文件作爲一個流?

現在有一個棘手的問題:如果我有多個文件,我需要一個連續的流,這意味着如果一個文件的最後一部分小於那個pieceLength,那麼我需要閱讀(pieceLength-got )下一個文件,然後繼續下去,直到最後一個文件結束。

所以,基本上,給定X文件,我會一直閱讀完全是pieceLength長的作品,除了最後一個最後一個文件,可能會更小。

我只是想知道是否已經有內置的.net(3.5 SP1)內置的東西。我目前的做法是創建一個類,它接受一個文件列表,然後公開一個類似於FileStream.Read()的函數Read(byte[] buffer, long index, long length)函數。這應該是非常直接的,因爲我不必更改讀取數據的調用代碼,但在重新開始之前,我只想仔細檢查車輪是否已經內置到BCL中。

謝謝:)

回答

6

我不相信有一個在框架什麼,但我會建議使它更靈活一點 - 拿在構造一個IEnumerable<Stream>,並從Stream派生自己。然後獲取文件流,你可以(假設C#3.0)只是做:

Stream combined = new CombinationStream(files.Select(file => File.Open(file)); 

的「所有權」部分是需要一點技巧在這裏 - 上面將允許組合流採取從讀取任何流的所有權,但你可能不希望它有通過流的所有其餘的迭代和全部關閉,如果過早關閉。

+0

這實際上是一個相當不錯的辦法,我只是還沒有確定,如果我想實現我自己的流。相反,一個IEnumerable ,一也可以工作,因爲那時我CombinationStream擁有「內部流」完全控制。我會考慮哪種方法最適合我。 – 2009-02-10 21:42:40

3

這是我基於@jon雙向飛碟的想法創造出來的。

它只是實現了Read對我來說已經足夠了。 (但沒有我需要執行的BeginRead/EndRead方法幫助。) 這裏是同時包含同步和異步全碼 - 讀取和的BeginRead/EndRead - https://github.com/prabirshrestha/CombinationStream/blob/master/ SRC/CombinationStream-Net20/CombinationStream.cs 移到https://github.com/facebook-csharp-sdk/CombinationStream/blob/master/src/CombinationStream-Net20/CombinationStream.cs

internal class CombinationStream : System.IO.Stream 
{ 
    private readonly System.Collections.Generic.IList<System.IO.Stream> _streams; 
    private int _currentStreamIndex; 
    private System.IO.Stream _currentStream; 
    private long _length = -1; 
    private long _postion; 

    public CombinationStream(System.Collections.Generic.IList<System.IO.Stream> streams) 
    { 
     if (streams == null) 
     { 
      throw new System.ArgumentNullException("streams"); 
     } 

     _streams = streams; 
     if (streams.Count > 0) 
     { 
      _currentStream = streams[_currentStreamIndex++]; 
     } 
    } 

    public override void Flush() 
    { 
     if (_currentStream != null) 
     { 
      _currentStream.Flush(); 
     } 
    } 

    public override long Seek(long offset, System.IO.SeekOrigin origin) 
    { 
     throw new System.InvalidOperationException("Stream is not seekable."); 
    } 

    public override void SetLength(long value) 
    { 
     this._length = value; 
    } 

    public override int Read(byte[] buffer, int offset, int count) 
    { 
     int result = 0; 
     int buffPostion = offset; 

     while (count > 0) 
     { 
      int bytesRead = _currentStream.Read(buffer, buffPostion, count); 
      result += bytesRead; 
      buffPostion += bytesRead; 
      _postion += bytesRead; 

      if (bytesRead <= count) 
      { 
       count -= bytesRead; 
      } 

      if (count > 0) 
      { 
       if (_currentStreamIndex >= _streams.Count) 
       { 
        break; 
       } 

       _currentStream = _streams[_currentStreamIndex++]; 
      } 
     } 

     return result; 
    } 

    public override long Length 
    { 
     get 
     { 
      if (_length == -1) 
      { 
       _length = 0; 
       foreach (var stream in _streams) 
       { 
        _length += stream.Length; 
       } 
      } 

      return _length; 
     } 
    } 

    public override long Position 
    { 
     get { return this._postion; } 
     set { throw new System.NotImplementedException(); } 
    } 
    public override void Write(byte[] buffer, int offset, int count) 
    { 
     throw new System.InvalidOperationException("Stream is not writable"); 
    } 

    public override bool CanRead 
    { 
     get { return true; } 
    } 

    public override bool CanSeek 
    { 
     get { return false; } 
    } 

    public override bool CanWrite 
    { 
     get { return false; } 
    } 
} 

也可作爲NuGet包

Install-Package CombinationStream 
相關問題