首页 > 代码库 > java 新IO

java 新IO

传统的IO

Java中的InputStream、OutputStream、Reader、Writer这样的面向流的输入输出系统被视为传统的IO。传统的IO是阻塞式的输入输出,并且是通过字节的移动来处理的,即传统的IO一次只能处理一个字节,效率不高。

新IO

新IO和传统的IO有相同的目的,都是用于进行输入输出功能。但是新IO采用内存映射文件的方式来处理输入输出,新IO将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样访问文件了,这种方式要比传统的IO快得多。

Java中新IO相关的包如下:

  • java.nio包:主要提供一些和Buffer相关的类;
  • java.nio.channel包:主要包括Channel和Selector相关的类;
  • java.nio.charset包:主要包含和字符集相关的类;
  • java.nio.channel.spi包:主要包含提供Channel服务的类;
  • java.nio.charset.spi包:主要包含提供字符集服务的类。

这里主要涉及到了四个类Channel、Buffer、Charset、Selector

Channel和Buffer是新IO中的两个核心对象,Channel是对传统输入输出的模拟,在新IO系统中所有数据都需要通过Channel进行传输。Channel与传统的InputStream和OutputStream最大的区别是它提供了一个map方法,通过该map方法可以直接将“一块数据”映射到内存中。如果说传统IO是面向流的处理,新IO则是面向块的处理。

Buffer可以被理解为一个容器,它的本质是一个数组,发送到Channel的所有对象都必须首先放到Buffer中,从Channel中读取的对象也必须先读到Buffer中。正如其名,Buffer起到的是缓冲的作用。

Charset用于将UNICODE字符串映射成字节序列以及逆映射操作。

Selector类用于支持非阻塞式输入输出操作。

Buffer的使用

Buffer的内部结构类似一个数组,可以保存多个类型相同的数据。 Buffer是一个抽象类,对应每种基本类型(boolean除外)都有相应的Buffer类,如ByteBuffer、ShortBuffer、CharBufferr、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer等等。这些Buffer类,除了ByteBuffer外,都采用相同或相似的方法来管理数据。这些Buffer都没有构造器,通过使用一个静态的XxxBuffer allocate(int capacity)创建一个容量为capacity的Buffer对象。

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

在Buffer中有3个重要概念:capacity(容量)、limit(界限)、position(位置)。

  • capacity:标识Buffer的最大容量即最多可以存储多少数据。capacity不能为负值,在创建后也不能改变。(这点和数组类似)
  • limit:第一个不能被读取也不能被写入的Buffer位置索引。也就是说,位于limit后的数据既不可被读也不可被写入。
  • position:用于指明下一个可以被读出或者写入的缓冲区位置索引(类似于传统IO中的记录指针)。当使用Buffer从Channel中读取数据时,position位置的值恰好等于已经堵到了多少数据。当新建一个Buffer对象时,其position为0。
  • 此外还有一个可选的标记mark,mark允许直接将position定位到mark处。

mark、position、limit、capacity满足如下关系:

mark<=position<=limit<=capacity。

Buffer的主要作用就是装入数据然后输出数据,在写入后读取数据中position和limit在发生变化:

  1. Buffer对象刚创建时,其position为0,limit为capacity;
  2. 程序调用put方法不断的向Buffer中填充数据,每填充一些数据,Buffer的position就向后移动一些位置;
  3. 当Buffer填充数据结束后,就会调用flip方法,将limit设置为position所在的位置,然后将position设置为0;
  4. 这样就可以从Buffer中读出数据,每读出一些数据,position就会向后移动一些位置;
  5. 数据读取完毕后,需要调用clear方法,clear方法不是将Buffer中的数据清空,而是将position重置为0,将limit重置为capacity,以等待数据的再次写入。

根据以上的步骤描述,可以发现Buffer的flip方法为读取数据做好了准备,clear方法为再次写入数据做好了准备。

put和get是Buffer的写入和读取数据的方法。Buffer既支持单个数据的读写,也支持批量读写(以数组为参数)。

当使用put和get来读写Buffer中的数据时,分为绝对和相对两种:

  • 相对:从Buffer的当前位置读取或写入数据,然后将position的值按处理的元素个数增加。
  • 绝对:直接根据索引向Buffer中读写数据,并不改变position的位置。

java 新IO