探索Java NIO的历程
前段时间有些时间,打算看看NIO的东西,本来以为很快可以了解的东西,却用了很多时间。
首先Goole NIO可以看到很多的教程,非阻塞,Buffer,内存映射,块读取前三个很快就有所了解
尝试着写了些小程序,学习东西的时候总喜欢写点小例子。
唯独块读取没有找到对应的东西。(在过程中,主要看了IBM 的NIO入门)
首先,IBM NIO入门中的语句
--------------------------------------------------------------------------------
原来的 I/O 库(在 java.io.*中) 与 NIO 最重要的区别是数据打包和传输的方式。正如前面提到的,
原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。 面向流 的 I/O 系统一次一个字节地处
理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。为流式数据创建过滤器非常容易。链接几个过滤器,以便每个过滤器只负责单个复杂处理机制的一部分,这样也是相对简单的。不利的一面是,面向流的 I/O 通常相当慢。 一个 面向块 的 I/O 系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的 I/O 缺少一些面向流的I/O 所具有的优雅性和简单性。
--------------------------------------------------------------------------------
首先简单的印象是NIO快,所以想写个程序验证一下.如下复制:
2 long start = System.currentTimeMillis();
3 try {
4 FileInputStream fis = new FileInputStream(name1);
5 FileOutputStream fos = new FileOutputStream(name2);
6 byte [] buf = new byte [ 8129 ];
7 while ( true ) {
8 int n = fis.read(buf);
9 if (n == - 1 ) {
10 break ;
11 }
12 fos.write(buf, 0 ,n);
13 }
14 fis.close();
15 fos.close();
16 } catch (Exception e) {
17 e.printStackTrace();
18 }
19 long end = System.currentTimeMillis();
20 long time = end - start;
21 System.out.println(time);
22 }
23
24 public static void test3(String name1, String name2) {
25 long start = System.currentTimeMillis();
26 try {
27 FileInputStream in = new FileInputStream(name1);
28 FileOutputStream out = new FileOutputStream(name2);
29 FileChannel fc1 = in.getChannel();
30 FileChannel fc2 = out.getChannel();
31 ByteBuffer bb = ByteBuffer.allocate( 8129 );
32 while ( true ) {
33 bb.clear();
34 int n = fc1.read(bb);
35 if (n == - 1 ) {
36 break ;
37 }
38 bb.flip();
39 fc2.write(bb);
40 }
41 fc1.close();
42 fc2.close();
43 } catch (IOException e) {
44
45 }
46 long end = System.currentTimeMillis();
47 long time = end - start;
48 System.out.println(time);
49 }
本以为可以结束,结果测试结果出乎意料,函数一比函数二要快,就是说Old IO快于NIO ,从此
也就开始了整个过程:
为了了解这个问题,仔细搜索并仔细再看IBM 的NIO教程,看到如下这段话
---------------------------------------------
在 JDK 1.4 中原来的 I/O 包和 NIO 已经很好地集成了。 java.io.* 已经以 NIO 为基础重新实现了,
所以现在它可以利用 NIO 的一些特性。例如, java.io.* 包中的一些类包含以块的形式读写数据的方法,
这使得即使在更面向流的系统中,处理速度也会更快。 也可以用 NIO 库实现标准 I/O 功能。例如,
可以容易地使用块 I/O 一次一个字节地移动数据。但是正如您会看到的,NIO 还提供了原 I/O 包中所没有的许多好处。
---------------------------------------------
所以我想,是否因为InputStream中使用了块读取实现了呢,所以进入JDK1.4中的InputStream中
看看source,首先引起我注意的是read函数,当参数是一个byte数组的时候,直接调用的native实现
难道是这个,为了验证,下载了一个JDK1.3下来,发现JDK1.3是一样的。
继续,我想是否是JVM底层实现了块读取呢,为了证明这个我用JDK1.3和JDK1.4同时实现了类似的函数, 测试的结果再次出乎意料,性能相差不大.那就不是这个了。
为此多方查找资料,未果,为此多写几个函数,好好测试一下IO的不同。于是有了如下的一些函数
2 public static void test1(String name1, String name2) {
3 long start = System.currentTimeMillis();
4 try {
5 String cmd = " cmd /c copy d:\\out1.txt d:\\out2.txt " ;
6 System.out.println(cmd);
7 Process p = Runtime.getRuntime().exec(cmd);÷
8 p.waitFor();
9 } catch (Exception e) {
10 e.printStackTrace();
11 }
12 long end = System.currentTimeMillis();
13 long time = end - start;
14 System.out.println(time);
15 }
16
17 // old io
18 public static void test2(String name1, String name2) {
19 long start = System.currentTimeMillis();
20 try {
21 FileInputStream fis = new FileInputStream(name1);
22 FileOutputStream fos = new FileOutputStream(name2);
23 while ( true ) {
24 byte [] buf = new byte [ 8129 ];
25 int n = fis.read(buf);
26 if (n == - 1 ) {
27 break ;
28 }
29 fos.write(buf);
30 }
31 fis.close();
32 fos.close();
33 } catch (Exception e) {
34 e.printStackTrace();
35 }
36 long end = System.currentTimeMillis();
37 long time = end - start;
38 System.out.println(time);
39 }
40
41 // new io
42 public static void test3(String name1, String name2) {
43 long start = System.currentTimeMillis();
44 try {
45 FileInputStream in = new FileInputStream(name1);
46 FileOutputStream out = new FileOutputStream(name2);
47 FileChannel fc1 = in.getChannel();
48 FileChannel fc2 = out.getChannel();
49 ByteBuffer bb = ByteBuffer.allocate( 8129 );
50 while ( true ) {
51 bb.clear();
52 int n = fc1.read(bb);
53 if (n == - 1 ) {
54 break ;
55 }
56 bb.flip();
57 fc2.write(bb);
58 }
59 fc1.close();
60 fc2.close();
61 } catch (IOException e) {
62