Java学习之IO与NIO篇

8月 5th, 2010 2,820 留下评论 阅读评论

Java的IO相较于其他语言,感觉是比较抽象和复杂的,当然等你理解了它并且熟练了,它的强大性就马上体现出来了。其实本来只是想写nio的,把io也顺带理一下吧。

Java的io最重要的一个概念就是流,就像一个水管插在文件和终端之间,每个字节都是一滴水,按顺序单方向地流动,这样理解不知道是不是容易些?流主要分以下几种类型:

  • 输入流和输出流:就是流的方向。 InputStream和Reader是输入,OutputStream和Writer是输出,很简单
  • 字节流和字符流:流的最小单位,字节流好理解,字符流是因为gbk和Unicode等的存在,单独一个字节是无法表示一个字符的,2个字节为单位读取。InputStream和OutputStream是字节流,Reader和Writer是字符流
  • 基础流和封装流:以上四种都是基础流,提供的API基本都是get()一个字节/字符,write()一个字节/字符;封装流将基础流包装了一下,提供了更多的功能,比如最常用的BufferedStream,用来缓存流从而提高IO效率;DataStream,提供读写Java基本类型的流,可以直接写入一个int、double、UTFString等;StreamReader、StreamWriter,将字节流转换为字符流;其他还有ByteArrayStream、FileStream等,字面意思就很明白了

弄清楚这些,其实Java IO基本就能搞明白了。传说中的三层流封装就很明了了,第一层基础流,比如InputSream,第二层InputStreamReader,转换为字符流,第三层再包装一个BufferedReader,提高IO效率,很清楚也很简单,不要被这个流程搞晕了。大致上基础io包也就这些东西了。

接下来就讲讲刚看的nio包,nio比基础io更抽象更难用,其实基础io功能也很强大了,所以一直没鼓起勇气去学nio。在百度文库下到一个不错的教程,2天就看完了,讲讲自己的心得。

先说nio中比较易用且实用的,就是各种Buffer,最基础的ByteBuffer,CharBuffer也不错,还有各种其他类型的Buffer。Buffer有position、limit、capacity属性。position为当前buffer操作到了哪个位置,包括读和写,limit为用户可自己限制的此buffer的结尾位置,capacity就是buffer的大小,综合起来就是:0 <=position <= limit <= capacity <= size of array。主要的API有flip(),主要用于将数据读入到buffer后,将limit设为当前的position,然后将position设为0,就可以从头到尾把所有的数据读出来了。

再说说文件读写中的FileChannel,这个是一个nio中新的概念,类似于stream,可以从FileStream中通过getChannel()获取,然后FileChannel的read(ByteBuffer)方法直接将字节流读入buffer,操作挺方便;官方介绍FileChannel说这是个可读可写并且双向的流,可读可写倒确实,不过双向我暂时没有看出来,文件copy的过程中还是需要建立1个InputStream获得一个FileChannel,1个OutputStream获得一个FileChannel,不能用1个FileChannel来搞定,双向意义何在?

综合FileChannel和Buffer举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FileInputStream fis = new FileInputStream(new File("a.txt"));
FileChannel fin = fis.getChannel();
FileOutputStream fos = new FileOutputStream(new File("b.txt"));
FileChannel fout = fos.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024); //1024字节的buffer
while(fin.read(buffer) != -1){
     buffer.flip(); //buffer写满,position重新置0,limit置为结尾,方便使用
     fout.write(buffer);
     buffer.clear();//清空buffer
}
fin.close();
fout.close();
fis.close();
fos.close();

还有一个也比较实用的是Charset和对应的CharsetEncoder和CharsetDecoder,可以将字节流与不同的字符流之间相互转换。

最后是nio中最麻烦应该也是最强大的地方,异步IO,这儿涉及很多新的概念和类,Selector、ServerSocketChannel、SelectionKey,注册事件、监听事件、处理事件等,我就看了一个下午左右,理解也不是非常深,大致知道这些类怎么串起来用。还是看程序来的学得快,程序我放到附件中,理解了NIOServer和NIOClient,就有了基础了。当然程序中比较缺乏的一点就是处理事件的时候是单线程的,这样事件队列一旦越积越多,速度就慢了,开几个线程同时来响应事件是比较好的方案。

nio中还有其他的一些东西,比如Buffer的一些深入 direct Buffer,越过临时buffer提高速度;Memory-mapped file I/O,提高文件读写速度;File locking(这个还不是很懂)。

又掌握了Java中一个很重要的类包,还是挺开心的,坚持写完这篇日志也是受了gstar博客大牛的影响,多写写技术blog哈~接下来的目标,当然是把nio好好再消化下,然后自我觉得没有掌握而觉得很重要的还有java.util.concurrency包、java.security包、java.rmi包,主要这些平时比较少用,嗯,慢慢来~

附:包括一个NIO的异步IO的2个示范类,随意看看

NIO异步IO示范

Categories: Java 标签:, ,
  1. steveyan | #沙发
    11月 6th, 2011 21:30

    双向Channel就是使用RandomAccessFile的读写模式获得的FileChannel.还有,套接字的Channel不清楚,但我想它也是双向的.