我目前正在编写一个缓存BaseStream.Position
和BaseStream.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
属性,让我公开Position
和BaseStream
属性,而不是提供Position
和Length
属性。作为FastBinaryReader.BaseStream.Position
和FastBinaryReader.BaseStream.Length
,以便我的现有代码与原始BinaryReader
类保持兼容。
我将如何做到这一点?
答案 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.Offset
和FastBinaryReader
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
语句的结果,而不是缓存Length
和Position
的结果?< / p>