有些文件太大,而不能全部放入内存操作,内存映射文件允许我们创建和修改那些因为太大而不能放入内存的文件。有了内存映射文件,
我们就可以假定整个文件都放在内存中,而且可以完全把它当做非常大的数组来访问。
MappedByteBuffer由ByteBuffer继承而来,因此它具有ByteBuffer的所有方法。使用MappedByteBuffer似乎我们可以一次访问到整个文件,
但是其实是只有一部分放入了内存,文件的其他部分被交换了出去。用这种方式,很大的文件(可达2G)也可以很容易的修改。
下面对“旧”的io和nio在映射文件访问上坐比较:
public class MappedIO { private static int numOfInts = 4000000; private static int numOfUbuffInts = 20000; private abstract static class Tester { private String name; public Tester(String name) { this.name = name; } public void runTest() { System.out.println(name + ": "); try { long start = System.nanoTime(); test(); double duration = System.nanoTime() - start; System.out.format("%.5f\n", duration / 1.0e9); } catch (IOException e) { e.printStackTrace(); } } public abstract void test() throws IOException; } private static Tester[] testers = { new Tester("Stream Write") { public void test() throws IOException { DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(new File("temp.tmp")))); for (int i = 0; i < numOfInts; i++) dos.writeInt(i); dos.close(); } }, new Tester("Mapped Write") { @Override public void test() throws IOException { FileChannel fc = new RandomAccessFile("temp.tmp", "rw").getChannel(); IntBuffer ib = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size()).asIntBuffer(); for (int i = 0; i < numOfInts; i++) ib.put(i); fc.close(); } }, new Tester("Stream Read") { @Override public void test() throws IOException { DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("temp.tmp"))); for (int i = 0; i < numOfUbuffInts; i++) dis.readInt(); dis.close(); } }, new Tester("Mapped Read") { @Override public void test() throws IOException { FileChannel fc = new FileInputStream(new File("temp.tmp")).getChannel(); IntBuffer ib = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).asIntBuffer(); while (ib.hasRemaining()) ib.get(); fc.close(); } }, new Tester("Stream Read/Write") { @Override public void test() throws IOException { RandomAccessFile raf = new RandomAccessFile(new File("temp.tmp"), "rw"); raf.writeInt(1); for (int i = 0; i < numOfUbuffInts; i++) { raf.seek(raf.length() - 4); raf.writeInt(raf.readInt()); } raf.close(); } }, new Tester("Mapped Read/Write") { @Override public void test() throws IOException { FileChannel fc = new RandomAccessFile(new File("temp.tmp"), "rw").getChannel(); IntBuffer ib = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size()).asIntBuffer(); ib.put(0); for (int i = 1; i < numOfUbuffInts; i++) ib.put(ib.get(i - 1)); fc.close(); } } }; public static void main(String[] args) { for (Tester test : testers) { test.runTest(); } } }效果:
Stream Write:
0.27245
Mapped Write:
0.01656
Stream Read:
0.00279
Mapped Read:
0.00789
Stream Read/Write:
0.33709
Mapped Read/Write:
0.00179
可以看到,整体收益比起Io流来说还是很显著的。