提高BinaryReader的性能

时间:2011-10-19 15:56:48

标签: c# caching binaryreader

我目前正在编写一个缓存BaseStream.PositionBaseStream.Length属性的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();
    }
}

我想创建一个Length属性,让我公开PositionBaseStream属性,而不是提供PositionLength属性。作为FastBinaryReader.BaseStream.PositionFastBinaryReader.BaseStream.Length,以便我的现有代码与原始BinaryReader类保持兼容。

我将如何做到这一点?

2 个答案:

答案 0 :(得分:3)

如果有人有兴趣,这是最终的实施。将此作为Stream对象传递给BinaryReader,而不是通常的FileStream对象,当读取1000字节块时,我的机器上的速度提高了约45%。

请注意,长度参数仅在读取时准确,因为长度在开始时读入并且不会更改。如果您正在编写,则不会随着基础流的长度更改而更新。

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

答案 1 :(得分:2)

我不会完全按照你在这里的方式做到这一点。

考虑您需要公开Stream类型的属性(BinaryReader.BaseStream是什么)。因此,您需要创建自己的类Stream。这个课需要:

  • 引用FastBinaryReader,以便通过委派给Stream.Length成员来覆盖Stream.OffsetFastBinaryReader
  • 引用Stream(在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内部:

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
}

这将允许您透明地使用StreamWrapper并保持缓存行为。但它提出了一个问题:你工作的Stream是如此愚蠢,以至于它本身不能缓存它?

如果不是,那么您看到的性能提升可能是ifReadBytes语句的结果,而不是缓存LengthPosition的结果?< / p>