大多數操做系統均可以利用虛擬內存實現將一個文件或者文件的一部分"映射"到內存中。而後,這個文件就能夠看成是內存數組來訪問,這比傳統的文件要快得多。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
能夠明顯看出,內存映射文件速度比普通輸入流和隨機訪問文件快得多,比帶緩衝的輸入流稍微快一些。內存