2011-10-19 22 views
2

現在、BaseStream.PositionBaseStream.LengthのプロパティをキャッシュするBinaryReaderを作成中です。ここで私はこれまで持っているものです:代わりにLengthPosition性を付与するBinaryReaderのパフォーマンスを改善する

public class FastBinaryReader 
{ 
    BinaryReader reader; 

    public long Length { get; private set; } 
    public long Position { get; private set; } 

    public FastBinaryReader(Stream stream) 
    { 
     reader = new BinaryReader(stream); 
     Length = stream.Length; 
     Position = 0; 
    } 

    public void Seek(long newPosition) 
    { 
     reader.BaseStream.Position = newPosition; 
     Position = newPosition; 
    } 

    public byte[] ReadBytes(int count) 
    { 
     if (Position + count >= Length) 
      Position = Length; 
     else 
      Position += count; 

     return reader.ReadBytes(count); 
    } 

    public void Close() 
    { 
     reader.Close(); 
    } 
} 

、私は私のように、私はFastBinaryReader.BaseStream.PositionFastBinaryReader.BaseStream.Lengthとして私PositionLengthプロパティを公開することができますBaseStreamプロパティを作成したいです既存のコードは元のBinaryReaderクラスと互換性を維持します。

どうすればいいですか?

+0

最初に「BinaryReader.BaseStream」によってこれらのプロパティにアクセスしないのはなぜですか?結局のところ、ストリームがそれらをサポートしていない場合、キャッシングの量はそれを動作させることはありません。 – Jon

+0

私の独自の位置と長さのプロパティを維持することで、End of Fileをチェックするときの読者のパフォーマンスが大幅に向上します。 1000バイトの読み込みテストでは、速度はほぼ倍増します。 –

答えて

2

私はこれをあなたがここに持っている方法とまったく同じではありません。

タイプStream(何のBinaryReader.BaseStream)のプロパティを公開する必要があると考えてください。したがって、Streamから派生した独自のクラスを作成する必要があります。それはStream(同じものがFastBinaryReaderコンストラクタに渡された)への参照を取る

  • FastBinaryReaderメンバーに委譲することによってStream.LengthStream.OffsetをオーバーライドすることができるようにFastBinaryReaderへの参照を取る

    • :このクラスは、する必要がありますそのストリームに他のすべての操作を委任するために、(あなたの代わりにこれらのthrow new NotImplementedException()持つことができますが、あなたは決してライブラリー法は、それらを呼び出すために起こっているかを知るん!)

    あなたはそれを見てねどのように想像することができます:

    private class StreamWrapper : Stream 
    { 
        private readonly FastBinaryReader reader; 
    
        private readonly Stream baseStream; 
    
        public StreamWrapper(FastBinaryReader reader, Stream baseStream) 
        { 
         this.reader = reader; 
         this.baseStream = baseStream; 
        } 
        public override long Length 
        { 
         get { return reader.Length; } 
        } 
    
        public override long Position 
        { 
         get { return reader.Position; } 
         set { reader.Position = value; } 
        } 
    
        // Override all other Stream virtuals as well 
    } 
    

    これは機能しますが、私にはややぎこちないようです。論理的な継続はStreamWrapperの代わりに、内部FastBinaryReader自体にキャッシュを置くために、次のようになります。これは、あなたが透過的StreamWrapperを使用して、キャッシュの動作を維持できるようになる

    private class StreamWrapper : Stream 
    { 
        private readonly Stream baseStream; 
    
        public StreamWrapper(Stream baseStream) 
        { 
         this.baseStream = baseStream; 
        } 
    
        public override long Length 
        { 
         get { /* caching implementation */ } 
        } 
    
        public override long Position 
        { 
         get { /* caching implementation */ } 
         set { /* caching implementation */ } 
        } 
    
        // Override all other Stream virtuals as well 
    } 
    

    。しかし、それは疑問を提起する:Streamあなたはそれだけでこれをキャッシュしないので、あまりにも愚かな作業ですか?

    そして、それがない場合は、多分あなたが見るパフォーマンスの向上は、キャッシングLengthPositionReadBytesはなく内部のそのif文の結果ですか?

  • +0

    'BaseStream.Position'と' BaseStream.Length'はOSへの高価な呼び出し( 'FileStream'を使用している場合)を呼びます。おそらく、複数のストリームを介してファイルに安全に同時にアクセスできるようになります。しかし、代わりにStreamクラスにパッチを当てるというあなたの考えが好きです。 +1 –

    +0

    その後、私は 'StreamWrapper'をキャッシングして' BinaryReader'を使っています。この方法でもっときれいに感じます。また、ストリームのパフォーマンスに頭をアップに感謝します。 – Jon

    +0

    以下に実装を掲載しました。 –

    3

    これは最終的な実装です。 FileStreamオブジェクトの代わりにStreamオブジェクトをBinaryReaderオブジェクトに渡すと、1000バイトのチャンクを読み込んだときにマシンの速度が約45%向上します。

    Length_paramは、である場合にのみ正確です。長さは開始時に読み込まれ、変更されないためです。あなたが書いているのであれば、基礎となるストリームの長さが変わると更新されません。

    public class FastFileStream : FileStream 
    { 
        private long _position; 
        private long _length; 
    
        public FastFileStream(string path, FileMode fileMode) : base(path, fileMode) 
        { 
         _position = base.Position; 
         _length = base.Length; 
        } 
    
        public override long Length 
        { 
         get { return _length; } 
        } 
    
        public override long Position 
        { 
         get { return _position; } 
         set 
         { 
          base.Position = value; 
          _position = value; 
         } 
        } 
    
        public override long Seek(long offset, SeekOrigin seekOrigin) 
        { 
         switch (seekOrigin) 
         { 
          case SeekOrigin.Begin: 
           _position = offset; 
           break; 
          case SeekOrigin.Current: 
           _position += offset; 
           break; 
          case SeekOrigin.End: 
           _position = Length + offset; 
           break; 
         } 
         return base.Seek(offset, seekOrigin); 
        } 
    
        public override int Read(byte[] array, int offset, int count) 
        { 
         _position += count; 
         return base.Read(array, offset, count); 
        } 
    
        public override int ReadByte() 
        { 
         _position += 1; 
         return base.ReadByte(); 
        } 
    } 
    
    関連する問題