2009-02-10 46 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 
相关问题