Java NIO

来源:互联网 发布:linux服务器开发书籍 编辑:程序博客网 时间:2024/06/08 20:08

输入/输出流都是阻塞式的(eg:InputStream的read方法从流中读取数据时,如果数据源中没有数据,它会阻塞该线程)

传统的输入流、输出流都是通过字节的移动来处理,面向流的输入/输出系统只能一次处理一个字节,因此效率不高。

Java新IO将文件或文件的一段区域映射到内存中,效率比较高。

Channel(通道)和Buffer(缓冲)是新IO中的两个核心对象在新IO系统中所有的数据都需要通过通道传输:Channel和传统的InputStream、OutputStream最大的区别在于它提供了一个map()方法,通过该map()方法可以直接将“一块数据”映射到内存中。

新IO还提供了用于将Unicode字符串映射成字符序列以及逆映射操作的Charset类,也提供了用于支持非阻塞式输入/输出的Selector类。


Buffer中有三个重要概念:

容量(capacity):最大数据量;

界限(limit):limit后的数据既不可以被读,也不可以被写。

位置(position):下一个可以被读取或者写入缓冲区位置的索引,第一个位置的索引是0。

import java.nio.CharBuffer;public class BufferTest {public static void main(String[] args) {CharBuffer charBuffer = CharBuffer.allocate(6);System.out.println("容量="+charBuffer.capacity());System.out.println("界限limit="+charBuffer.limit());System.out.println("位置="+charBuffer.position());charBuffer.put('1');charBuffer.put('1');charBuffer.put('2');System.out.println("加入三个元素后的位置索引="+charBuffer.position());charBuffer.flip();System.out.println("调用flip()方法后,limit="+charBuffer.limit());System.out.println("调用flip()方法后,位置索引="+charBuffer.position());//开始取数据System.out.println("取出第一个元素="+charBuffer.get(0));System.out.println("取出第一个元素后,位置索引="+charBuffer.position());//调用clear()charBuffer.clear();System.out.println("调用clear()方法后,limit="+charBuffer.limit());System.out.println("调用clear()方法后,位置索引="+charBuffer.position());System.out.println("取出第三个元素="+charBuffer.get(2));charBuffer.put('1');charBuffer.put('2');charBuffer.put('3');charBuffer.put('4');charBuffer.put('5');charBuffer.put('6');System.out.println("重新put值之后,取出第三个元素="+charBuffer.get(2));System.out.println("取出第三个元素后,位置索引="+charBuffer.position());}}


调用Buffer的flip()后,该方法将limit设置为position所在位置,并将position设置为0,即Buffer的读写指针又回到了开始位置,调用flip()方法之后,Buffer为输出数据做好准备;当Buffer输出数据结束后,Buffer调用clear()方法,clear()方法不是清空数据,它只是将position的设置为0,将limit设置成capacity,这样再次向Buffer中装入数据做好准备,put数据的时候将会覆盖之前的数据。

实际使用较多的是ByteBuffer和CharBuffer,ByteBuffer类还有一个子类:MappedByteBuffer,它用于表示Channel将磁盘文件部分或全部内容映射到内存中后得到的结果,通常MappedByteBuffer对象由Channel的map()方法返回。


Channel(通道)

(1)Channel可以直接将指定文件的部分或全部直接映射成Buffer。

(2)程序不能直接访问Channel中的数据,读写都不允许,Channel只能与Buffer进行交互。新IO中的Channel是按功能划分的,eg:Pipe.SinkChannel、Pipe.SourceChannel是用于支持线程之间通信的管道Channel;ServerSocketChannel、SocketChannel是用于支持TCP网络通信的Channel;而DatagramChannel则是用于支持UDP网络通信的Channel。

Channel最常用的三个方法是:map()、read()、write(),其中map()方法用于将Channel对应的部分或全部数据映射成ByteBuffer;而read()或write()方法都有一系列重载形式。

import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.nio.MappedByteBuffer;import java.nio.channels.FileChannel;public class FileChannelTest {@SuppressWarnings("resource")public static void main(String[] args) {File file = new File("InputStreamTest.java");try {FileChannel inFileChannel = new FileInputStream(file).getChannel();FileChannel outFileChannel = new FileOutputStream("file.txt").getChannel();//将inFileChannel里的全部数据映射到ByteBuffer中MappedByteBuffer mappedByteBuffer = inFileChannel.map(FileChannel.MapMode.READ_ONLY, 0, file.length());//直接将buff中数据全部读出outFileChannel.write(mappedByteBuffer);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

读取任意字节数据,防止使用map()方法一次将所有的文件内容映射到内存引起性能下降

import java.io.FileInputStream;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.CharBuffer;import java.nio.channels.FileChannel;import java.nio.charset.Charset;public class ReadFile {public static void main(String[] args) {try(FileChannel fileChannel = new FileInputStream("InputStreamTest.java").getChannel();) {//一次去1024字节ByteBuffer byteBuffer = ByteBuffer.allocate(1024);while(fileChannel.read(byteBuffer)!=-1){//锁定byteBuffer中的空白区,开始读取数据byteBuffer.flip();//创建CharsetDecoder对象Charset charset = Charset.forName("GBK");//将ByteBuffer中的内容转码CharBuffer charBuffer = charset.decode(byteBuffer);System.out.println(charBuffer);//为下次装入数据做准备byteBuffer.clear();}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}


原创粉丝点击