FileChannel与ByteBuffer的使用示例
FileChannel的作用:
channel可以只操作一个文件的一部分,chunk操作, 比如替换大文件的文件头
文件截断truncate
IO性能
ByteBuffer
HeapByteBuffer = ByteBuffer.allocate(n)申请堆上的buffer
DirectByteBuffer = ByteBuffer.allocateDirect(n)申请系统直接内存,使用场景和作用
生命周期长的大对象,
减少java堆GC, 减少内存copy
http://www.importnew.com/26334.html
Buffer.flip()干啥用的?
buffer.put(xxx)之后, buffer的position会指到当前xxx的size,如果想进行写操作,需要把position重新指到0.
String file = "xxx.txt"; //abcdef
byte[] bb = new byte[4];
bb[0] = 0b1111;
bb[1] = 0b1111;
bb[2] = 0b1111;
bb[3] = 0b1111;
try (RandomAccessFile writer = new RandomAccessFile(file, "rw");
FileChannel channel = writer.getChannel()) {
// ByteBuffer buff = ByteBuffer.wrap(new String(bb).getBytes());
ByteBuffer buff = ByteBuffer.allocate(6);
buff.put(bb); // java.nio.HeapByteBuffer[pos=0 lim=6 cap=6] ==> java.nio.HeapByteBuffer[pos=4 lim=6 cap=6]
buff.flip(); // java.nio.HeapByteBuffer[pos=4 lim=6 cap=6] ==> java.nio.HeapByteBuffer[pos=0 lim=4 cap=6]
channel.write(buff);
channel.force(true);
}
如果不加flip(), pos到lim之间的数据4-6会写到文件(pos=lim时,nothing is write to file).
channel.write(buff)只写pos到lim之间的数据。
只替换指定大小的文件部分,剩余部分文件内容不变。
Buffer.compact()干啥用的?
字面意思是·压缩·,把pos到limit的数据copy到从0开始的位置,然后pos变成数据大小+1
这个方法是用在write()之后的,不是用在write前面
文件copy的性能
public class DirectByteBufferTest {
@Test
public void test_copyFile() throws IOException {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(10);//100kbytes
FileChannel readChannel = FileChannel.open(new File("D:/in.txt").toPath());
//out.txt必须已经存在, writeChannel必须以WRITE方式打开
FileChannel writeChannel = FileChannel.open(new File("D:/out.txt").toPath(), StandardOpenOption.WRITE);
int read;
while ((read = readChannel.read(byteBuffer)) != -1) {
//buffer从读切换到写
byteBuffer.flip();
// 打印信息必须放在flip后面, 否则decode出来的是上次read的结果.根据in.txt的字符编码修改下面的ISO_8859_1
//System.out.println(read + "--" + StandardCharsets.ISO_8859_1.decode(byteBuffer));
writeChannel.write(byteBuffer);
// 写完之后清空缓冲区,否则read=0一直死循环
byteBuffer.clear();
}
writeChannel.close();
readChannel.close();
}
}
其他总结:
ByteBuffer.allocateDirect缓冲区大小根据输入文件的大小调整,但是太大时输出性能也提高不了多少, 对于大文件,1M的缓存区应该差不多了。
对于超大文件, 应该换成其他读取方式
benchmark: https://developer.ibm.com/articles/j-zerocopy
@@@build beautiful things, share happiness@@@