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
class 是 hard-coded to reject ZIP files where the first file header doesn't appear at offset 0。为了避免临时文件(因为文件可以大到 3.99GB),我想愚弄 ZipPackage
以为它正在处理文件的开头,而实际上它正在读写偏移量。
当然可以。这是 装饰器模式的完美案例:
基本上你创建了一个 class
- 继承自
Stream
(您正在装饰的摘要class)
- 有一个接受该基础的单个实例的构造函数class
然后您覆盖所有方法和属性,将调用传递给装饰实例。如果该方法或 属性 知道流的位置或长度,您可以根据需要应用适当的调整。
编辑说明: 看起来你需要装饰抽象流,如下所示(没有实际打开文件的情况下无法创建文件流实例).
这是装饰器本身的 [截断] 示例:
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 ) ;
}
}
简单! (除了涉及的所有样板)
问题
有没有办法在 C# 中创建带有偏移量的 FileStream
?例如,如果我在偏移量 100 处打开 SomeFile.bin,则 Stream.Position
将等于 0,但读取和写入将偏移 100。
背景
我正在为我的公司开发一种混合文件格式,它将机器可读的二进制数据与现代 PC 可读的 OPC 文件(本质上是使用 System.IO.Packaging
创建的 ZIP 文件)相结合。出于性能原因,二进制数据必须出现在文件的顶部。我知道 ZIP 文件允许这样做(例如自解压档案),但不幸的是内部 ZipIOCentralDirectoryBlock
class 是 hard-coded to reject ZIP files where the first file header doesn't appear at offset 0。为了避免临时文件(因为文件可以大到 3.99GB),我想愚弄 ZipPackage
以为它正在处理文件的开头,而实际上它正在读写偏移量。
当然可以。这是 装饰器模式的完美案例:
基本上你创建了一个 class
- 继承自
Stream
(您正在装饰的摘要class) - 有一个接受该基础的单个实例的构造函数class
然后您覆盖所有方法和属性,将调用传递给装饰实例。如果该方法或 属性 知道流的位置或长度,您可以根据需要应用适当的调整。
编辑说明: 看起来你需要装饰抽象流,如下所示(没有实际打开文件的情况下无法创建文件流实例).
这是装饰器本身的 [截断] 示例:
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 ) ;
}
}
简单! (除了涉及的所有样板)