探索Java NIO的历程

本文探讨了Java NIO的特点及其实现方式,并通过对比传统IO与NIO的文件复制性能,深入分析了NIO块读取的优势。通过具体代码示例展示了不同IO操作的执行效率。

探索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快,所以想写个程序验证一下.如下复制:

 

 1 ExpandedBlockStart.gifContractedBlock.gifpublic   static   void  test2(String name1, String name2)  dot.gif {
 2 InBlock.gif         long  start  =  System.currentTimeMillis();
 3 ExpandedSubBlockStart.gifContractedSubBlock.gif         try   dot.gif {
 4 InBlock.gif            FileInputStream fis  =   new  FileInputStream(name1);
 5 InBlock.gif            FileOutputStream fos  =   new  FileOutputStream(name2);
 6 InBlock.gif             byte [] buf  =   new   byte [ 8129 ];
 7 ExpandedSubBlockStart.gifContractedSubBlock.gif             while  ( true dot.gif {                
 8 InBlock.gif                 int  n  =  fis.read(buf);
 9 ExpandedSubBlockStart.gifContractedSubBlock.gif                 if  (n  ==   - 1 dot.gif {
10 InBlock.gif                     break ;
11 ExpandedSubBlockEnd.gif                }

12 InBlock.gif                fos.write(buf, 0 ,n);
13 ExpandedSubBlockEnd.gif            }

14 InBlock.gif            fis.close();
15 InBlock.gif            fos.close();
16 ExpandedSubBlockStart.gifContractedSubBlock.gif        }
  catch  (Exception e)  dot.gif {
17 InBlock.gif            e.printStackTrace();
18 ExpandedSubBlockEnd.gif        }

19 InBlock.gif         long  end  =  System.currentTimeMillis();
20 InBlock.gif         long  time  =  end  -  start;
21 InBlock.gif        System.out.println(time);
22 ExpandedBlockEnd.gif    }

23 None.gif    
24 ExpandedBlockStart.gifContractedBlock.gif     public   static   void  test3(String name1, String name2)  dot.gif {
25 InBlock.gif         long  start  =  System.currentTimeMillis();
26 ExpandedSubBlockStart.gifContractedSubBlock.gif         try   dot.gif {
27 InBlock.gif            FileInputStream in  =   new  FileInputStream(name1);
28 InBlock.gif            FileOutputStream out  =   new  FileOutputStream(name2);
29 InBlock.gif            FileChannel fc1  =  in.getChannel();
30 InBlock.gif            FileChannel fc2  =  out.getChannel();
31 InBlock.gif            ByteBuffer bb  =  ByteBuffer.allocate( 8129 );
32 ExpandedSubBlockStart.gifContractedSubBlock.gif             while  ( true dot.gif {
33 InBlock.gif                bb.clear();
34 InBlock.gif                 int  n  =  fc1.read(bb);
35 ExpandedSubBlockStart.gifContractedSubBlock.gif                 if  (n  ==   - 1 dot.gif {
36 InBlock.gif                     break ;
37 ExpandedSubBlockEnd.gif                }

38 InBlock.gif                bb.flip();
39 InBlock.gif                fc2.write(bb);
40 ExpandedSubBlockEnd.gif            }

41 InBlock.gif            fc1.close();
42 InBlock.gif            fc2.close();
43 ExpandedSubBlockStart.gifContractedSubBlock.gif        }
  catch  (IOException e)  dot.gif {
44 InBlock.gif
45 ExpandedSubBlockEnd.gif        }

46 InBlock.gif         long  end  =  System.currentTimeMillis();
47 InBlock.gif         long  time  =  end  -  start;
48 InBlock.gif        System.out.println(time);
49 ExpandedBlockEnd.gif    }

本以为可以结束,结果测试结果出乎意料,函数一比函数二要快,就是说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的不同。于是有了如下的一些函数

  1 None.gif//  exec
  2 ExpandedBlockStart.gifContractedBlock.gif      public   static   void  test1(String name1, String name2)  dot.gif {
  3 InBlock.gif         long  start  =  System.currentTimeMillis();
  4 ExpandedSubBlockStart.gifContractedSubBlock.gif         try   dot.gif {
  5 InBlock.gif            String cmd  =   " cmd /c copy d:\\out1.txt d:\\out2.txt " ;
  6 InBlock.gif            System.out.println(cmd);
  7 InBlock.gif            Process p  =  Runtime.getRuntime().exec(cmd);÷
  8 InBlock.gif            p.waitFor();
  9 ExpandedSubBlockStart.gifContractedSubBlock.gif        }
  catch  (Exception e)  dot.gif {
 10 InBlock.gif            e.printStackTrace();
 11 ExpandedSubBlockEnd.gif        }

 12 InBlock.gif         long  end  =  System.currentTimeMillis();
 13 InBlock.gif         long  time  =  end  -  start;
 14 InBlock.gif        System.out.println(time);
 15 ExpandedBlockEnd.gif    }

 16 None.gif
 17 None.gif     //  old io
 18 ExpandedBlockStart.gifContractedBlock.gif      public   static   void  test2(String name1, String name2)  dot.gif {
 19 InBlock.gif         long  start  =  System.currentTimeMillis();
 20 ExpandedSubBlockStart.gifContractedSubBlock.gif         try   dot.gif {
 21 InBlock.gif            FileInputStream fis  =   new  FileInputStream(name1);
 22 InBlock.gif            FileOutputStream fos  =   new  FileOutputStream(name2);
 23 ExpandedSubBlockStart.gifContractedSubBlock.gif             while  ( true dot.gif {
 24 InBlock.gif                 byte [] buf  =   new   byte [ 8129 ];
 25 InBlock.gif                 int  n  =  fis.read(buf);
 26 ExpandedSubBlockStart.gifContractedSubBlock.gif                 if  (n  ==   - 1 dot.gif {
 27 InBlock.gif                     break ;
 28 ExpandedSubBlockEnd.gif                }

 29 InBlock.gif                fos.write(buf);
 30 ExpandedSubBlockEnd.gif            }

 31 InBlock.gif            fis.close();
 32 InBlock.gif            fos.close();
 33 ExpandedSubBlockStart.gifContractedSubBlock.gif        }
  catch  (Exception e)  dot.gif {
 34 InBlock.gif            e.printStackTrace();
 35 ExpandedSubBlockEnd.gif        }

 36 InBlock.gif         long  end  =  System.currentTimeMillis();
 37 InBlock.gif         long  time  =  end  -  start;
 38 InBlock.gif        System.out.println(time);
 39 ExpandedBlockEnd.gif    }

 40 None.gif
 41 None.gif     //  new io
 42 ExpandedBlockStart.gifContractedBlock.gif      public   static   void  test3(String name1, String name2)  dot.gif {
 43 InBlock.gif         long  start  =  System.currentTimeMillis();
 44 ExpandedSubBlockStart.gifContractedSubBlock.gif         try   dot.gif {
 45 InBlock.gif            FileInputStream in  =   new  FileInputStream(name1);
 46 InBlock.gif            FileOutputStream out  =   new  FileOutputStream(name2);
 47 InBlock.gif            FileChannel fc1  =  in.getChannel();
 48 InBlock.gif            FileChannel fc2  =  out.getChannel();
 49 InBlock.gif            ByteBuffer bb  =  ByteBuffer.allocate( 8129 );
 50 ExpandedSubBlockStart.gifContractedSubBlock.gif             while  ( true dot.gif {
 51 InBlock.gif                bb.clear();
 52 InBlock.gif                 int  n  =  fc1.read(bb);
 53 ExpandedSubBlockStart.gifContractedSubBlock.gif                 if  (n  ==   - 1 dot.gif {
 54 InBlock.gif                     break ;
 55 ExpandedSubBlockEnd.gif                }

 56 InBlock.gif                bb.flip();
 57 InBlock.gif                fc2.write(bb);
 58 ExpandedSubBlockEnd.gif            }

 59 InBlock.gif            fc1.close();
 60 InBlock.gif            fc2.close();
 61 ExpandedSubBlockStart.gifContractedSubBlock.gif        }
  catch  (IOException e)  dot.gif {
 62 Outlini
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值