优化BufferedRandomAccessFile。
优化原则:
- 多重嵌套逻辑判断时,最可能出现的判断,应放在最外层。
这里举一典型的例子:
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);
return len;
}
public int read(byte b[]) throws IOException {
return this.read(b, 0, b.length);
}
public void setLength(long newLength) throws IOException {
if (newLength > 0) {
this.fileendpos = newLength - 1;
} else {
this.fileendpos = 0;
}
super.setLength(newLength);
}
public void close() throws IOException {
this.flushbuf();
super.close();
}
至此完善工作基本完成,试一下新增的多字节读/写功能,通过同时读/写1024个字节,来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 |
BufferedRandomAccessFile完 |
BufferedRandomAccessFile完 |
0.401 |
与MappedByteBuffer+RandomAccessFile的对比?
JDK1.4+提供了NIO类
,其中MappedByteBuffer类用于映射缓冲,也可以映射随机文件访问,可见JAVA设计者也看到了RandomAccessFile的问题,
并加以改进。怎么通过MappedByteBuffer+RandomAccessFile拷贝文件呢?下面就是测试程序的主要部分:
RandomAccessFile rafi = new RandomAccessFile(SrcFile, "r");
RandomAccessFile rafo = new RandomAccessFile(DesFile, "rw");
FileChannel fci = rafi.getChannel();
FileChannel fco = rafo.getChannel();
long size = fci.size();
MappedByteBuffer mbbi = fci.map(FileChannel.MapMode.READ_ONLY, 0, size);
MappedByteBuffer mbbo = fco.map(FileChannel.MapMode.READ_WRITE, 0, size);
long start = System.currentTimeMillis();
for (int i = 0; i < size; i++) {
byte b = mbbi.get(i);
mbbo.put(i, b);
}
fcin.close();
fcout.close();
rafi.close();
rafo.close();
System.out.println("Spend: "+(double)(System.currentTimeMillis()-start) / 1000 + "s");
试一下JDK1.4的映射缓冲读/写功能,逐字节COPY一个12兆的文件,(这里牵涉到读和写):
读 |
写 |
耗用时间(秒) |
RandomAccessFile |
RandomAccessFile |
95.848 |
BufferedInputStream +
DataInputStream |
BufferedOutputStream +
DataOutputStream |
2.935 |
BufferedRandomAccessFile |
BufferedOutputStream +
DataOutputStream |
2.813 |
BufferedRandomAccessFile |
BufferedRandomAccessFile |
2.453 |
BufferedRandomAccessFile优 |
BufferedRandomAccessFile优 |
2.197 |
BufferedRandomAccessFile完 |
BufferedRandomAccessFile完 |
0.401 |
MappedByteBuffer+
RandomAccessFile |
MappedByteBuffer+
RandomAccessFile |
1.209 |
确实不错,看来NIO有了极大的进步。建议采用
MappedByteBuffer+RandomAccessFile的方式。
分享到:
相关推荐
RandomAccessFile处理文件的案例
花1K内存实现高效I-O的RandomAccessFile类 自己搜搜这个关键字. 我主要是用来优化Android上多线程断点下载的写文件效率 RandomAccessFile是操作硬盘的,比操作内存的数据慢了几百万倍, 所有有人做出优化,我特上传...
NULL 博文链接:https://x7700.iteye.com/blog/1003918
花1K内存实现高效IO的RandomAccessFile类.doc
RandomAccessFile 解决乱码
RandomAccessFile类的用法.docRandomAccessFile类的用法.docRandomAccessFile类的用法.doc
体会RandomAccessFile随机访问文件的用法
Java中正确使用RandomAccessFile向文件中写入中文
RandomAccessFile(下).mp4
java api中的java.io.RandomAccessFile类实现文件的随机写入.
因为使用其他文件流修改文件时是整体的替换,导致SVN上传上去后是整个文件都修改了,所以需要增量修改,这个demo是使用RandomAccessFile增量修改,只修改指定的行,很实用
文件操作——File 、 RandomAccessFile(上).mp4
文件操作——File 、 RandomAccessFile(上).mp4
使用RandomAccessFile流将一个文本文件读出,并导致写入到另一个文件当中。
在JAVA程序设计不少涉及到对文件的读写操作,本例针对这方面的问题,介绍RandomAccessFile类的文件读写操作,文件中包含有1个java文件和1个class文件
【IT十八掌徐培成】Java基础第16天-01.RandomAccessFile.zip
本篇文章是对用1K内存实现高效I/O的RandomAccessFile类的详细分析介绍,需要的朋友参考下
RandomAccessFile随机文本,使用多线程处理复制文件
NIO_RandomAccessFile_多线程读本地CSV文件(java==> google guava包ListenableFuture) reader里有个main函数,更改文件路径后,直接运行即可
NULL 博文链接:https://baihe747.iteye.com/blog/2124747