C#创建带有偏移量的文件流 问题:

C#创建带有偏移量的文件流 问题:,c#,file-io,zip,C#,File Io,Zip,有没有办法在C#中创建一个带有偏移量的FileStream?例如,如果我在偏移量100处打开SomeFile.bin,Stream.Position将等于0,但读写将偏移100 背景 我正在为我的公司开发一种混合文件格式,它将机器可读的二进制数据与现代PC可读的OPC文件(基本上是使用System.IO.Packaging创建的ZIP文件)相结合。出于性能原因,二进制数据必须显示在文件的顶部。我知道ZIP文件将允许这样做(例如自解压归档),但不幸的是,内部ZipIOCentralDirector

有没有办法在C#中创建一个带有偏移量的
FileStream
?例如,如果我在偏移量100处打开SomeFile.bin,
Stream.Position
将等于0,但读写将偏移100

背景
我正在为我的公司开发一种混合文件格式,它将机器可读的二进制数据与现代PC可读的OPC文件(基本上是使用
System.IO.Packaging
创建的ZIP文件)相结合。出于性能原因,二进制数据必须显示在文件的顶部。我知道ZIP文件将允许这样做(例如自解压归档),但不幸的是,内部
ZipIOCentralDirectoryBlock
类是。为了避免使用临时文件(因为文件可能大到3.99GB),我想愚弄
ZipPackage
,让它认为它是在处理文件的开头,而实际上它是以偏移量读写的。

当然。这是装饰图案的完美案例:

基本上,您创建了一个

  • 继承自
    (您正在装饰的抽象类)
  • 具有接受该基类的单个实例的构造函数
然后重写所有方法和属性,将调用传递给修饰实例。如果方法或属性知道流的位置或长度,则根据需要应用适当的调整

编辑为注意:看起来您需要如下所示装饰抽象流(如果不实际打开文件,就无法创建filestream实例)

下面是装饰器本身的一个[截断]示例:

class OffsetStreamDecorator : Stream
{
  private readonly Stream instance ;
  private readonly long       offset   ;

  public static Stream Decorate( Stream instance )
  {
    if ( instance == null ) throw new ArgumentNullException("instance") ;

    FileStream decorator= new OffsetStreamDecorator( instance ) ;
    return decorator;
  }

  private OffsetStreamDecorator( FileStream instance )
  {
    this.instance = instance ;
    this.offset   = instance.Position ;
  }

  #region override methods and properties pertaining to the file position/length to transform the file positon using the instance's offset

  public override long Length
  {
    get { return instance.Length - offset ; }
  }

  public override void SetLength( long value )
  {
    instance.SetLength( value + offset );
  }

  public override long Position
  {
    get { return instance.Position - this.offset         ; }
    set {        instance.Position = value + this.offset ; }
  }

  // etc.

  #endregion

  #region override all other methods and properties as simple pass-through calls to the decorated instance.

  public override IAsyncResult BeginRead( byte[] array , int offset , int numBytes , AsyncCallback userCallback , object stateObject )
  {
    return instance.BeginRead( array , offset , numBytes , userCallback , stateObject );
  }

  public override IAsyncResult BeginWrite( byte[] array , int offset , int numBytes , AsyncCallback userCallback , object stateObject )
  {
    return instance.BeginWrite( array , offset , numBytes , userCallback , stateObject );
  }

  // etc.

  #endregion

}
用法非常简单,大致如下:

using ( Stream baseStream = new FileStream( @"c:\foo\bar\somefile.dat" , FileMode.Open , FileAccess.Read , FileShare.Read ) )
{

  // establish your offset
  baseStream.Seek( 100 , SeekOrigin.Begin ) ;

  using ( Stream decoratedStream = OffsetStreamDecorator.Decorate( baseStream ) )
  {
    // now you have a stream that reports a false position and length
    // which you should be able to use anywhere a Stream is accepted.

    PassDecoratedStreamToSomethingExpectingAVanillaStream( decoratedStream ) ;

  }

}

轻松点!(除了所有涉及的样板文件)

创建一个包装器类来实现这一点并不难。创建包装器的最简单方法是什么?我应该从FileStream继承,还是从Stream继承并拥有一个FileStream实例?从FileStream继承是很自然的,但由于构造函数太多,我会避免它。也许你错过了关于它是一个ZIP文件的一点。如果涉及到压缩,你就无法猜测偏移量…@leppie:zip文件是一种包含一个或多个单独压缩文件的存档格式。这里只涉及WRT-zip文件本身的偏移量。zip文件目录位于zip文件的末尾。目录中的每个条目都告诉您压缩条目在zip文件中的位置和长度。你寻找它,阅读八位组并解压缩它们。我们在这里所做的就是为流建立一个不同的“零点”。对不起,我误解了这个问题。但是我的大脑编译器告诉我,在你的代码中有很多编译器错误:)(现在是向上投票,但请修复你的类型错误)谢谢,这看起来可以满足我的要求。不过有一个简单的问题,如果我要在像您的示例那样的内部using块中使用Close()和Dispose(),我是否仍然应该重写Close()和Dispose()?似乎这会导致文件流被关闭并被释放两次,或者更糟糕的是,在被释放后被意外使用。没关系。我不会重写Close()和Dispose()。