大多数操做系统均可以利用虚拟内存实现将一个文件或者文件的一部分"映射"到内存中。而后,这个文件就能够看成是内存数组来访问,这比传统的文件要快得多。java
内存映射文件的一个关键优点是操做系统负责真正的读写,即便你的程序在刚刚写入内存后就挂了,操做系统仍然会将内存中的数据写入文件系统。另一个更突出的优点是共享内存,内存映射文件能够被多个进程同时访问,起到一种低时延共享内存的做用。数组
那么,如何将一个文件映射到内存呢?app
FileChannel channel = FileChannel.open(path,options);
这里options指定映射模式,支持的模式有三种:dom
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY,0,length);
接下来经过计算一个40MB文件的CRC32校验和来比较传统的文件输入和内存映射文件的速度。操作系统
传统的文件输入包括:code
程序以下:进程
import java.io.*; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.zip.CRC32; /** * Created by lbd on 2017/1/11. */ public class MemoryMapTest { public static long checksumInputStream(Path filename) throws IOException { //普通输入流 try (InputStream in = Files.newInputStream(filename)) { CRC32 crc = new CRC32(); int c; while ((c = in.read()) != -1) crc.update(c); return crc.getValue(); } } public static long checksumBufferedInputStream(Path filename) throws IOException { //带缓冲的输入流 try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(filename))){ CRC32 crc = new CRC32(); int c; while ((c = in.read()) != -1) crc.update(c); return crc.getValue(); } } public static long checksumRandomAccessFile(Path filename) throws IOException { //随机访问文件 try (RandomAccessFile file = new RandomAccessFile(filename.toFile(),"r")){ CRC32 crc = new CRC32(); long length = file.length(); for (long p = 0; p < length; p++){ file.seek(p); int c = file.readByte(); crc.update(c); } return crc.getValue(); } } public static long checksumMappedFile(Path filename) throws IOException { //内存映射文件 try (FileChannel channel = FileChannel.open(filename)){ CRC32 crc = new CRC32(); int length = (int)channel.size(); MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY,0,length); for (int p = 0; p < length; p++){ int c = buffer.get(p); crc.update(c); } return crc.getValue(); } } public static void main(String[] args) throws IOException { System.out.println("Input Stream:"); long start = System.currentTimeMillis(); Path filename = Paths.get(args[0]); long crcValue = checksumInputStream(filename); long end = System.currentTimeMillis(); System.out.println(Long.toHexString(crcValue)); System.out.println((end - start) + " milliseconds"); System.out.println(); System.out.println("Buffered Input Stream:"); start = System.currentTimeMillis(); crcValue = checksumBufferedInputStream(filename); end = System.currentTimeMillis(); System.out.println(Long.toHexString(crcValue)); System.out.println((end - start) + " milliseconds"); System.out.println(); System.out.println("Random Access File:"); start = System.currentTimeMillis(); crcValue = checksumRandomAccessFile(filename); end = System.currentTimeMillis(); System.out.println(Long.toHexString(crcValue)); System.out.println((end - start) + " milliseconds"); System.out.println(); System.out.println("Mapped File:"); start = System.currentTimeMillis(); crcValue = checksumMappedFile(filename); end = System.currentTimeMillis(); System.out.println(Long.toHexString(crcValue)); System.out.println((end - start) + " milliseconds"); } }
输出结果以下:ip
Input Stream: c644b1f1 42317 milliseconds Buffered Input Stream: c644b1f1 329 milliseconds Random Access File: c644b1f1 57781 milliseconds Mapped File: c644b1f1 207 milliseconds
能够明显看出,内存映射文件速度比普通输入流和随机访问文件快得多,比带缓冲的输入流稍微快一些。内存