花1K内存实现高效IO的RandomAccessFile类
v1.0 可编辑可修改 JAVA的文件随机存取类(RandomAccessFile)的I/O效率较低。通过分析其中原因,提出解决方案。逐步展示如何创建具备缓存读写能力的文件随机存取类,并进行了优化。通过与其它文件访问类的性能对比,证明了其实用价值。 主体 目前最流行的J2SDK版本是系列。使用该版本的开发人员需文件随机存取,就得使用RandomAccessFile类。其I/O性能较之其它常用开发语言的同类性能差距甚远,严重影响程序的运行效率。 开发人员迫切需要提高效率,下面分析RandomAccessFile等文件类的源代码,找出其中的症结所在,并加以改进优化,创建一个性/价比俱佳的随机文件访问类BufferedRandomAccessFile。 1.在改进之前先做一个基本测试逐字节COPY一个12兆的文件(这里牵涉到读和写)。 读 写 耗用时间(秒) RandomAccessFile RandomAccessFile BufferedStream DataStream BufferedOutputStream DataOutputStream 我们可以看到两者差距约32倍,RandomAccessFile也太慢了。先看看两者关键部分的源代码,对比分析,找出原因。 1.1.[RandomAccessFile] public class RandomAccessFile implements DataOutput, Data { public final byte readByte throws IOException { int ch ; if ch 0 throw new EOFException; return bytech; } public native int read throws IOException; public final void writeByteint v throws IOException { writev; } public native void writeint b throws IOException; } 可见,RandomAccessFile每读/写一个字节就需对磁盘进行一次I/O操作。 1.2.[BufferedStream] public class BufferedStream extends FilterStream { private static int defaultBufferSize 2048; protected byte buf[]; . pos * bufbitlen / bufbitlen; . } seek函数使用在各函数中,调用非常频繁,上面加重的这行语句根据pos和bufsize确定buf[]对应当前文件的映射位置,用*、/确定,显然不是一个好方法。 优化一 pos bufbitlen bufbitlen; 优化二 pos bufmask; // long - 1; 两者效率都比原来好,但后者显然更好,因为前者需要两次移位运算、后者只需一次逻辑与运算(bufmask可以预先得出)。 至此优化基本实现,逐字节COPY一个12兆的文件,(这里牵涉到读和写,结合缓冲读,用优化后BufferedRandomAccessFile试一下读/写的速度) 读 写 耗用时间(秒) RandomAccessFile RandomAccessFile BufferedStream DataStream BufferedOutputStream DataOutputStream BufferedRandomAccessFile BufferedOutputStream DataOutputStream BufferedRandomAccessFile BufferedRandomAccessFile BufferedRandomAccessFile优 BufferedRandomAccessFile优 可见优化尽管不明显,还是比未优化前快了一些,也许这种效果在老式机上会更明显。 以上比较的是顺序存取,即使是随机存取,在绝大多数情况下也不止一个BYTE,所以缓冲机制依然有效。而一般的顺序存取类要实现随机存取就不怎么容易了。 4.需要完善的地方 提供文件追加功能 public boolean appendbyte bw throws IOException { return bw, 1; } 提供文件当前位置修改功能 public boolean writebyte bw throws IOException { return bw, ; } 返回文件长度(由于BUF读写的原因,与原来的RandomAccessFile类有所不同) public long length throws IOException { return 1, ; } 返回文件当前指针(由于是通过BUF读写的原因,与原来的RandomAccessFile类有所不同) public long getFilePointer throws IOException { return ; } 提供对当前位置的多个字节的缓冲写功能 public void writebyte b[], int off, int len throws IOException { long writeendpos len - 1; if writeendpos { // b[] in cur buf b, off, , int - , len; true; intwriteendpos - 1; } else { // b[] not in cur buf ; b, off, len; } if writeendpos writeendpos; writeend