概念
内存映射文件是将文件(部分)内容映射到内存中,读写操作都在内存中完成,最后再写回文件
示例
package io;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class MappedBufferDemo {
public static void main(String[] args) throws IOException {
RandomAccessFile file = new RandomAccessFile("/tmp/test", "rw");
FileChannel fileChannel = file.getChannel();
MappedByteBuffer byteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, file.length());
for (int i = 0; i < file.length(); i++) {
byte src = byteBuffer.get(i);
if (src == 'a') {
byteBuffer.put(i, (byte)('A'));
}
}
byteBuffer.force();
byteBuffer.clear();
fileChannel.close();
file.close();
}
}
该程序是将文件整个映射到内存中,并查找a字符替换为A,在修改的过程中,文件已经被修改了,最后调用force是强制刷盘。
原理
在传统的文件IO操作中,我们都是调用操作系统提供的底层标准IO系统调用函数 read()、write() ,此时调用此函数的进程(在JAVA中即java进程)由当前的用户态切换到内核态,然后OS的内核代码负责将相应的文件数据读取到内核的IO缓冲区,然后再把数据从内核IO缓冲区拷贝到进程的私有地址空间中去,这样便完成了一次IO操作。
在内存映射文件的时候将某一段的虚拟地址和文件对象的某一部分建立起映射关系(mmap),此时并没有拷贝数据到内存中去,而是当进程代码第一次引用这段代码内的虚拟地址时,触发了缺页异常,这时候OS根据映射关系直接将文件的相关部分数据拷贝到进程的用户私有空间中去,当有操作第N页数据的时候重复这样的OS页面调度程序操作。注意啦,原来内存映射文件的效率比标准IO高的重要原因就是因为少了把数据拷贝到OS内核缓冲区这一步。
适用场景
- 修改文件中的局部数据
- 处理大文件:并没有把文件所有内容都拷贝到内存,只是在用的时候进行了拷贝