内存映射文件
(Memory-mapped File),指的是将一段虚拟内存逐字节映射于一个文件,使得应用程序处理文件如同访问主内存(但在真正使用到这些数据前却不会消耗物理内存,也不会有读写磁盘的操作),这要比直接文件读写快几个数量级。
稍微解释一下虚拟内存(很明显,不是物理内存),它是计算机系统内存管理的一种技术。像施了妖法一样使得应用程序认为它拥有连续的可用的内存,实际上呢,它通常是被分隔成多个物理内存的碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。
内存映射文件主要的用处是增加 I/O 性能,特别是针对大文件。对于小文件,内存映射文件反而会导致碎片空间的浪费,因为内存映射总是要对齐页边界,最小单位是 4 KiB,一个 5 KiB 的文件将会映射占用 8 KiB 内存,也就会浪费 3 KiB 内存。
java.nio 包使得内存映射变得非常简单,其中的核心类叫做 MappedByteBuffer,字面意思为映射的字节缓冲区。
01、使用 MappedByteBuffer 读取文件
假设现在有一个文件,名叫 cmower.txt,里面的内容是:
沉默王二,一个有趣的程序员
PS:哎,改不了王婆卖瓜自卖自夸这个臭毛病了,因为文章被盗得都怕了。
这个文件放在
/resource
目录下,我们可以通过下面的方法获取到它:
ClassLoader classLoader = Cmower.class.getClassLoader();
Path path = Paths.get(classLoader.getResource("cmower.txt").getPath());
Path 既可以表示一个目录,也可以表示一个文件,就像 File 那样——当然了,Path 是用来取代 File 的。
然后,从文件中获取一个 channel(通道,对磁盘文件的一种抽象)。
FileChannel fileChannel = FileChannel.open(path);
紧接着,调用 FileChannel 类的 map 方法从 channel 中获取 MappedByteBuffer,此类扩展了
ByteBuffer
——提供了一些内存映射文件的基本操作方法。
MappedByteBuffer mappedByteBuffer = fileChannel.map(mode, position, size);
稍微解释一下 map 方法的三个参数。
1)mode 为文件映射模式,分为三种:
-
MapMode.READ_ONLY(只读),任何试图修改缓冲区的操作将导致抛出 ReadOnlyBufferException 异常。
-
MapMode.READ_WRITE(读/写),任何对缓冲区的更改都会在某个时刻写入文件中。需要注意的是,其他映射同一个文件的程序可能不能立即看到这些修改,多个程序同时进行文件映射的行为依赖于操作系统。
-
MapMode.PRIVATE(私有), 对缓冲区的更改不会被写入到该文件,任何修改对这个缓冲区来说都是私有的。
2)position 为文件映射时的起始位置。
3)
size
为要映射的