繁体   English   中英

C#创建具有偏移量的FileStream

[英]C# Create a FileStream with an offset

有没有一种方法可以在C#中使用偏移量创建FileStream 例如,如果我在偏移量100处打开SomeFile.bin ,则Stream.Position等于0,但读写偏移量为100。

背景

我正在为我的公司开发一种混合文件格式,该格式将机器可读的二进制数据与现代的PC可读的OPC文件(实际上是使用System.IO.Packaging创建的ZIP文件)结合在一起。 出于性能原因,二进制数据必须出现在文件的顶部。 我知道ZIP文件将允许这样做(例如,自解压档案),但是不幸的是,内部ZipIOCentralDirectoryBlock类被硬编码为拒绝第一个文件头不在偏移量0出现的ZIP文件 为了避免使用临时文件(因为文件可以达到3.99GB),我想让ZipPackage认为它正在处理文件的开头,而实际上却是在偏移地读写。

当然。 这是Decorator模式的完美案例:

基本上,您创建一个

  • 继承自Stream (您正在装饰的抽象类)
  • 有一个接受该基类的单个实例的构造函数

然后,您将覆盖所有方法和属性,并将调用传递到经过修饰的实例。 如果方法或属性知道流的位置或长度,则可以根据需要应用适当的调整。

编辑注意: 看起来您需要装饰抽象流,如下所示(在没有实际打开文件的情况下无法创建文件流实例)。

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

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 ) ;

  }

}

简单! (所有涉及的样板除外)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM