3

我目前正在编写一个缓存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();
    }
}

我不想提供LengthandPosition属性,而是想创建一个BaseStream属性,允许我将我的PositionandLength属性公开为FastBinaryReader.BaseStream.Positionand FastBinaryReader.BaseStream.Length,这样我现有的代码将与原始BinaryReader类保持兼容。

我该怎么做呢?

4

2 回答 2

3

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

请注意, Length 参数仅在读取时准确,因为 Length 在开始时被读取并且不会更改。如果您正在编写,它不会随着底层流的长度变化而更新。

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();
    }
}
于 2011-10-19T17:51:55.563 回答
2

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

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

  • 引用 toFastBinaryReader以便它可以覆盖Stream.LengthStream.Offset委托给FastBinaryReader成员
  • 获取对 a 的引用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你的工作是否如此愚蠢以至于它不会自己缓存这个?

如果不是,那么您看到的性能提升可能是if内部语句的结果,ReadBytes而不是缓存LengthPosition

于 2011-10-19T16:16:26.550 回答