🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
<!-- Performance --> ### 性能 虽然旧的 I/O 流的性能通过使用 **NIO** 实现得到了改进,但是映射文件访问往往要快得多。下例带来一个简单的性能比较。代码示例: ```java // newio/MappedIO.java // 我们无法保证该代码是否适用于其他用途。 // 访问 http://OnJava8.com 了解更多本书信息。 import java.util.*; import java.nio.*; import java.nio.channels.*; import java.io.*; public class MappedIO { private static int numOfInts = 4_000_000; private static int numOfUbuffInts = 100_000; private abstract static class Tester { private String name; Tester(String name) { this.name = name; } public void runTest() { System.out.print(name + ": "); long start = System.nanoTime(); test(); double duration = System.nanoTime() - start; System.out.format("%.3f%n", duration/1.0e9); } public abstract void test(); } private static Tester[] tests = { new Tester("Stream Write") { @Override public void test() { try( DataOutputStream dos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( new File("temp.tmp")))) ) { for(int i = 0; i < numOfInts; i++) dos.writeInt(i); } catch(IOException e) { throw new RuntimeException(e); } } }, new Tester("Mapped Write") { @Override public void test() { try( 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); } catch(IOException e) { throw new RuntimeException(e); } } }, new Tester("Stream Read") { @Override public void test() { try( DataInputStream dis = new DataInputStream( new BufferedInputStream( new FileInputStream("temp.tmp"))) ) { for(int i = 0; i < numOfInts; i++) dis.readInt(); } catch(IOException e) { throw new RuntimeException(e); } } }, new Tester("Mapped Read") { @Override public void test() { try( 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(); } catch(IOException e) { throw new RuntimeException(e); } } }, new Tester("Stream Read/Write") { @Override public void test() { try( 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()); } } catch(IOException e) { throw new RuntimeException(e); } } }, new Tester("Mapped Read/Write") { @Override public void test() { try( 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)); } catch(IOException e) { throw new RuntimeException(e); } } } }; public static void main(String[] args) { Arrays.stream(tests).forEach(Tester::runTest); } } ``` 输出结果: ``` Stream Write: 0.615 Mapped Write: 0.050 Stream Read: 0.577 Mapped Read: 0.015 Stream Read/Write: 4.069 Mapped Read/Write: 0.013 ``` **Tester** 使用了模板方法(Template Method)模式,它为匿名内部子类中定义的 `test()` 的各种实现创建一个测试框架。每个子类都执行一种测试,因此 `test()` 方法还提供了执行各种I/O 活动的原型。 虽然映射的写似乎使用 **FileOutputStream**,但是文件映射中的所有输出必须使用 **RandomAccessFile**,就像前面代码中的读/写一样。 请注意,`test()` 方法包括初始化各种 I/O 对象的时间,因此,尽管映射文件的设置可能很昂贵,但是与流 I/O 相比,总体收益非常可观。