日期:2014-05-16  浏览次数:21099 次

高效的RandomAccessFile【续】

优化BufferedRandomAccessFile。

?

优化原则:

  • ??? 调用频繁的语句最需要优化,且优化的效果最明显。
  • ??? 多重嵌套逻辑判断时,最可能出现的判断,应放在最外层。
  • ??? 减少不必要的NEW。


这里举一典型的例子:

?

   public void seek(long pos) throws IOException {
		...
         this.bufstartpos =  pos * bufbitlen / bufbitlen; // bufbitlen指buf[]的位长,例:若bufsize=1024,则bufbitlen=10。
                ...
  }
?

seek函数使用在各函数中,调用非常频繁,上面加重的这行语句根据pos和bufsize确定buf[]对应当前文件的映射位置,用"*"、"/"确定,显然不是一个好方法。

?

  • 优化一:this.bufstartpos = (pos << bufbitlen) >> bufbitlen;
  • 优化二:this.bufstartpos = pos & bufmask; // this.bufmask = ~((long)this.bufsize - 1);

两者效率都比原来好,但后者显然更好,因为前者需要两次移位运算、后者只需一次逻辑与运算(bufmask可以预先得出)。

至此优化基本实现,逐字节COPY一个12兆的文件,(这里牵涉到读和写,结合缓冲读,用优化后BufferedRandomAccessFile试一下读/写的速度):

?

耗用时间(秒)
RandomAccessFile RandomAccessFile 95.848
BufferedInputStream + DataInputStream BufferedOutputStream + DataOutputStream 2.935
BufferedRandomAccessFile BufferedOutputStream + DataOutputStream 2.813
BufferedRandomAccessFile BufferedRandomAccessFile 2.453
BufferedRandomAccessFile优 BufferedRandomAccessFile优 2.197

?

可见优化尽管不明显,还是比未优化前快了一些,也许这种效果在老式机上会更明显。

以上比较的是顺序存取,即使是随机存取,在绝大多数情况下也不止一个BYTE,所以缓冲机制依然有效。而一般的顺序存取类要实现随机存取就不怎么容易了。


需要完善的地方

?

提供文件追加功能:

?

public boolean append(byte bw) throws IOException {
   return this.write(bw, this.fileendpos + 1);
}

?

提供文件当前位置修改功能:

?

public boolean write(byte bw) throws IOException {
   return this.write(bw, this.curpos);
}

?

返回文件长度(由于BUF读写的原因,与原来的RandomAccessFile类有所不同):

?

public long length() throws IOException {
   return this.max(this.fileendpos + 1, this.initfilelen);
}

?

返回文件当前指针(由于是通过BUF读写的原因,与原来的RandomAccessFile类有所不同):

?

public long getFilePointer() throws IOException {
   return this.curpos;
}

?

提供对当前位置的多个字节的缓冲写功能:

?

public void write(byte b[], int off, int len) throws IOException {
        long writeendpos = this.curpos + len - 1;
        if (writeendpos <= this.bufendpos) { // b[] in cur buf
            System.arraycopy(b, off, this.buf, (int)(this.curpos - this.bufstartpos), len);
            this.bufdirty = true;
            this.bufusedsize = (int)(writeendpos - this.bufstartpos + 1);
        } else { // b[] not in cur buf
            super.seek(this.curpos);
            super.write(b, off, len);
        }
        if (writeendpos > this.fileendpos)
            this.fileendpos = writeendpos;
        this.seek(writeendpos+1);
}
public void write(byte b[]) throws IOException {
        this.write(b, 0, b.length);
}

?

提供对当前位置的多个字节的缓冲读功能:

?

public int read(byte b[], int off, int len) throws IOException {
    long readendpos = this.curpos + len - 1;
    if (readendpos <= this.bufendpos && readendpos <= this.fileendpos ) { // read in buf
     	System.arraycopy(this.buf, (int)(this.curpos - this.bufstartpos), b, off, len);
    } else { // read b[] size > buf[]
   	if (readendpos > this.fileendpos) { // read b[] part in file
      	len = (int)(this.length() - this.curpos + 1);
    }
       super.seek(this.curpos);
       len = super.read(b, off, len);
       readendpos = this.curpos + len - 1;
   }
       this.seek(readendpos + 1);
       retu