2014-10-30 260 views
1

我继承BinaryReader类。访问BinaryReader的内部缓冲区

我必须重写一些基本的方法,如ReadUInt16

内部实现这个方法是:

public virtual ushort ReadUInt16(){ 
    FillBuffer(2); 
    return (ushort)(m_buffer[0] | m_buffer[1] << 8); 
} 

的二进制文件,我从首先(大端)组织为高字节读,我从BinaryReader继承也因为我有添加更多的功能。 无论如何,我想在子类本身实现交换。

是否有另一种方法来访问m_buffer或替代方案,而不使用反射或其他消耗资源?
可能是我应该覆盖FillBuffer并备份偷看的字节?或者只是忽略它?会有副作用吗?有没有人遇到过这个?任何人都可以解释为什么FillBuffer不是内部的?是否需要始终填充缓冲区或可以跳过?现在,它不是内部的,为什么不是一个受保护的获得者m_buffer字段实施?

下面是FillBuffer的实现。

protected virtual void FillBuffer(int numBytes) { 
    if (m_buffer != null && (numBytes < 0 || numBytes > m_buffer.Length)) { 
     throw new ArgumentOutOfRangeException("numBytes", 
      Environment 
      .GetResourceString("ArgumentOutOfRange_BinaryReaderFillBuffer")); 
    } 
    int bytesRead=0; 
    int n = 0; 

    if (m_stream==null) __Error.FileNotOpen(); 

    // Need to find a good threshold for calling ReadByte() repeatedly 
    // vs. calling Read(byte[], int, int) for both buffered & unbuffered 
    // streams. 
    if (numBytes==1) { 
     n = m_stream.ReadByte(); 
     if (n==-1) 
      __Error.EndOfFile(); 
     m_buffer[0] = (byte)n; 
     return; 
    } 

    do { 
     n = m_stream.Read(m_buffer, bytesRead, numBytes-bytesRead); 
     if (n==0) { 
      __Error.EndOfFile(); 
     } 
     bytesRead+=n; 
    } while (bytesRead<numBytes); 
} 

回答

4

尝试访问内部缓冲区不是一个好主意。为什么不这样做:

var val = base.ReadUInt16(); 
return (ushort)((val << 8) | ((val >> 8) & 0xFF)); 

略多于从缓冲区直接读取慢,但我严重怀疑,这将会使你的应用程序的整体速度产生重大影响。

FillBuffer显然是一个实现细节,由于某些原因,框架团队决定需要制作protected,可能是因为其他一些Framework类利用BinaryReader的内部工作。既然你知道它所做的只是填充内部缓冲区,而派生类不能访问内部缓冲区,所以如果你决定自己重写阅读实现,我建议你忽略这个方法。称它对你没有任何好处,并且会对你造成很大的伤害。

您可能会感兴趣的series of articles我几年前写的,其中我实现了一个BinaryReaderWriter类,它本质上是一个BinaryReaderBinaryWriter连接在一起,并允许您底层流随机读/写访问。

+0

你说在访问缓冲区之前需要调用该方法,但如果缓冲区根本无法访问呢?他们应该使这个方法成为内部的,或者提供一个getter包装到缓冲区。因为我处理大型二进制文件,所以我更喜欢性能,我只是忽略FillBuffer。请在你的回答中更具体地提及它,以便其他用户更清楚。你认为保存交换是多余的优化(我需要覆盖所有的数字阅读器)。 – Shimmy 2014-10-31 03:34:16

+1

是的,我确实认为节省交换是冗余优化。与从磁盘文件读取数据所花费的时间相比,几百万次掉期不算什么。至于'FillBuffer'方法,我不担心它。这显然是一个实现细节,因为框架团队认为他们需要公开的某些未知原因。可能是因为不同的.NET类使用它。正如你所说,因为它的功能是填充派生类无法访问的内部缓冲区,所以调用它不会有什么好处。 – 2014-10-31 03:46:25

+0

吉姆,包括'&0xFF'在内的点有什么意思?这不是没有使用它的结果吗?你可以请参考一篇文章解释吗? 顺便说一句,我刚刚订阅了你的博客,我喜欢它! – Shimmy 2014-10-31 04:40:54