2009-02-10 6 views
5

Tengo una lista de archivos, y necesito leerlos en un orden específico en bytes [] de un tamaño determinado. Esto en sí mismo no es un problema para un solo archivo, un simple mientras que ((got = fs.Read (piece, 0, pieceLength))> 0) hace el trabajo perfectamente bien. La última parte del archivo puede ser más pequeña que lo deseado, lo cual está bien.¿Hay una forma incorporada de manejar archivos múltiples como una secuencia?

Ahora, hay un truco: si tengo varios archivos, necesito tener una transmisión continua, lo que significa que si la última parte de un archivo es más pequeña que esa pieza, entonces necesito leer (pieceLength-got) del siguiente archivo, y luego continúe hasta el final del último archivo.

Esencialmente, dado X archivos, siempre leeré piezas que son exactamente largas, excepto la última parte del último archivo, que puede ser más pequeño.

Me pregunto si ya hay algo de compilación en .net (3.5 SP1) que lo solucione. Mi enfoque actual es crear una clase que tome una lista de archivos y luego expone una función Read(byte[] buffer, long index, long length), similar a FileStream.Read(). Esto debería ser bastante sencillo porque no tengo que cambiar mi código de llamada que lee los datos, pero antes de reinventar la rueda solo me gustaría verificar que la rueda no esté incorporada en el BCL.

Gracias :)

Respuesta

6

No creo que haya nada en el marco, pero me gustaría sugerir lo que es un poco más flexible - tomar una IEnumerable<Stream> en su constructor, y se derivan de Stream mismo. archivo a continuación, para obtener secuencias se puede (suponiendo que C# 3.0) acaba de hacer:

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

La parte "propiedad" es un poco difícil aquí - de lo anterior permitiría que la corriente de combinación para tomar posesión de cualquier corriente que lee de, pero puede no desea que tenga que recorrer el resto de las secuencias y cerrarlas todas si es cerrado prematuramente.

+0

que en realidad es bastante buena forma, no estoy seguro todavía apenas si quiero implementar mi propia transmisión En lugar de un IEnumerable , un también podría funcionar, porque entonces mi CombinationStream tiene control total sobre las "corrientes internas". Pensaré en cuál enfoque me conviene más. –

3

Esto es lo que surgió basado en la idea de @jon skeet.

Simplemente implementa Read, que fue suficiente para mí. (pero no, necesito ayuda para implementar el método BeginRead/EndRead.) Aquí está el código completo que contiene tanto sincronización como asincronía - Read and BeginRead/EndRead - https://github.com/prabirshrestha/CombinationStream/blob/master/ src/CombinationStream-Net20/CombinationStream.cs trasladó a 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; } 
    } 
} 

también disponible como un paquete NuGet

Install-Package CombinationStream 
Cuestiones relacionadas