Java新IO

一.Java新IO概述


1.传统的输入, 输出流都是通过字节的移动来处理的, (即使不直接去处理字节流, 但底层的实现还是依赖于字节处理). 从JDK1.4开始, Java提供了一系列 改进的输入/输出处理的新特性, 这些功能被统称为新IO, 这些类都被放在java.nio 包及其子包下.

2. 新IO和传统IO有相同的目的, 都是用于进行输入/输出功能, 但新IO使用了不同的方式来处理输入输出, 新IO采用内存映射文件的方式来处理输入输出, 新IO将文件或文件中的一段区域映射到内存中, 这样就可以像访问内存一样来访问文件(模拟了操作系统上虚拟内存的概念), 通过这种方式来进行输入输出比传统的输入输出要快得多.

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

4.Buffer可以被理解成一个容器, 它的本质是一个数组, 发送到Channel中的所有对象都必须首先放到Buffer中去, 而从Channel中读取的数据也必须先读到Buffer中.

5.除了Channel和Buffer之外, 新IO还提供了用于将UNICODE字符串映射成字节序列以及逆映射操作的Charset类, 还提供了用于支持非阻塞式输入输出的Selector类.

二.Buffer


1.从内部结构上看Buffer就像一个数组, 它可以保存多个类型相同的数据. Buffer是一个抽象类, 其最常用的子类是ByteBuffer, 它可以在底层字节数组上进行get/set操作, 除了ByteBuffer之外, 对应其他基本数据类型(boolean类型)都有相应的Buffer类: ByteBuffer, CharBuffer, ShortBuffer, IntBuffer, LongBuffer, DoubleBuffer, FloatBuffer.

上面这些Buffer类, 除了ByteBuffer之外, 它们都采用相同或相似的方法来管理数据, 只是各自管理的数据类型不同. 这些Buffer都没有提供构造器, 通过如下方法来得到一个Buffer对象:

        static XxxBuffer allocate(int capacity):创建一个容量为capacity的XxxBuffer对象

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

2.Buffer中三个重要的概念:

        容量(capacity), 界限(limit), 位置(position)

容量:  缓冲区的容量表示该Buffer的最大数据容量, 缓冲区的容量不能为负, 在创建后也不能改变.

界限:  第一个不应该被读出或者写入的缓冲区位置索引, 位于limit后的数据既不可读, 也不可写.

位置:  用于指明下一个可以被读出的或者写入的缓冲区位置索引, 当刚刚新建一个Buffer对象时, 其position为0 , 如果从Channel中读取了2个数据到该Buffer中, 则position为2.

3.Buffer的主要作用就是装入数据, 然后输出数据, 开始时Buffer的position为0, limit为capacity, 程序调用put不断向Buffer中放入数据, 每放一些数据, position相应的向后移动一些位置.

4. flip方法: 该方法将limit设置为position所在位置, 将position设置为0 , 当Buffer调用flip方法后, Buffer为输出数据做好了准备.

   clear方法: 当Buffer输出数据结束之后, 调用clear方法, clear方法不是清空Buffer的数据, 它仅仅将position置为0, 将limit置为capacity, 再次向Buffer中装入数据做好准备.(执行clear方法之后,Buffer缓冲区内容并没有被清除, 还可以继续访问它)

5.当使用put和get来访问Buffer中的数据时, 分为绝对和相对两种:

        相对:从Buffer的当前位置读取或者写入数据, 然后将位置(position)的值按处理元素的个数增加

        绝对:直接根据索引来向Buffer中读取或者写入数据, 使用绝对方式来访问Buffer里的数据时, 并不会影响position的值.

三.Channel

1.Channel类似于传统的流对象, 但与传统的流不同的是, Channel有两个主要的区别:

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

    (2)程序不能直接访问Channel中的数据, 包括读取, 写入都不行, Channel只能与Buffer进行交互. 如果要从Channel中取得数据, 必须先使用Buffer从Channel中取出这些数据; 如果要将程序中的数据写入Channel中, 一样先让程序将数据放入Buffer中, 再将Buffer里的输入写入Channel中.

2. Channel是一个接口, 位于java.nio.channels包下. 系统为该接口提供了很多子实现类.

3. 所有的Channel都是通过传统的节点InputStream, OutputStream的getChannel 方法来返回对应的Channel. 不同的节点流获得的Channel不一样.

4. Channel中最常用的三类方法是map, read和write. map方法用于将Channel对应的部分或全部数据映射成ByteBuffer; 而read或write方法都有一系列重载形式, 这些方法用于从Buffer中读取数据或者向Buffer里写入数据.



四.编码集和Charset 

计算机里的所有文件在底层都是二进制文件, 即全部都是字节码. 对于文本文件而言, 之所以我们可以看到一个一个的字符, 这完全是因为系统将底层的字节序列转换成字符序列的缘故. 在这个过程中涉及两个概念: 编码(Encode)和解码(Decode). 把明文的字符串序列转换成计算机理解的字节序列(二进制文件)称为编码, 把字节序列转换成能看懂的明文字符串称为解码.

对于一份文本文件, 必须采用合适的字符集来解码它, 才可以将这份文本文件解码成正确的文本内容. 使用强制的字符集来解码将看到乱码现象.

JDk1.4提供了Charset来处理字节序列和字符序列之间的转换关系. Charset类是不可变的.

<***>GBK---->一个中文对应两个字节

          utf-8----->一个中文对应三个字节


获得Charset对象之后可以通过该对象的newEncoder(), newDecoder()方法分别返回CharsetEncoder和CharsetDecoder对象, 代表该Charset的解码器和编码器. 调用CharsetDecoder的decode方法就可以将ByteBuffer(字节序列)转换成CharBuffer(字符序列), 调用CharsetEncoder的encode方法就可以将CharBuffer或String转换成ByteBuffer(字节序列).


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值