新IO流概述
自JDK1.4开始,java提供了一系列新的的输入/输出流,统称为新IO(NewIO),与以往IO流处理不同的是(以往的IO流处理都是通过字节的移动来处理,即一个一个字节的操作),而新IO流是通过内存映射文件来进行操作的(即将文件或一段文件区域映射到内存中),通过访问内存就像访问文件一样,效果就是使得输出/输出操作更快。
Java相关包:
→java.nio包:主要提供了一些和Buffer相关的类。
→java.nio.channels包:主要包括Channel和Selector相关的类。
→java.nio.charset包:主要包含和字符集相关的类。
→java.nio.channels.spi包:主要包含Channel服务的类。
→java.nio.charset.spi包:主要包含和Charset服务的类。
新IO中有两个核心:Channel(通道)和 Buffer(缓冲)
一、Buffer
Buffer相当于数组,可以保存多个类型的数据,为抽象类。
在Buffer中三个重要的概念:
→容量(Capacity):缓冲区的最大容量,该容量不能为负数,不能更改。
→界限(limit):第一个不能够被读取和写入的位置索引,该位置索引后的内容不能够读取,也不能够写入。
→位置(position):用于指明下一个可以被读取或写入的缓冲区索引位置(相当于IO流中的记录指针),默认状态下为0,然后读取/写入多少数据就后移多少位置。
使用Buffer步骤:
这些Buffer子类无构造器,所以只能以 static XxxBuffer allocate(int capacity):创建一个大小为capacity的XxxBuffer对象。方法创建。
Buffer用于装载数据,然后读取数据。对象初始化时,position为0,limit等于capacity。
装入数据 --> position移动相应的大小 --> 装入数据结束,调用flip方法(将limit设置到position位置,position设为0),为读取数据准备 --> 读取数据 --> position移动相应的大小,直到读取到limiit读取完成 --> 调用clear方法(将limit设置到capacity位置,position设置为0),为下次装入数据做准备
常用方法:
→public final Buffer flip():反转此缓冲区。limit设置到position位置 然后position设为0. 如果标记mark存在,则抛弃。
→public final Buffer clear():清理此缓冲区。limit设置到capacity位置,position位置设为0,丢弃mark。
→public final int capacity():返回此Buffer的capacity大小。
→public final int remaining():返回当前位置position和limit之间的元素个数。
→public final boolean hasRemaining():判断当前位置position和limit之间是否有元素可以处理。
→public final int position():返回此Buffer当前位置position。
→public final Buffer position(int newPosition):设置新位置position,返回一个改变position后的Buffer对象。
→public final Buffer reset():将位置position转到mark所在的位置。
→public final Buffer rewind():将位置position设置为0,并取消设置的mark。
→public final Buffer mark():设置该Buffer中mark的位置。(mark只能在0和position之间选择)
Buffer所有子类的两个重要方法:
put(放入数据)和get(取出数据)方法:
→使用相对方法(Relative):从Buffer当前位置读取/写入数据,position按照处理的元素个数增加。
→使用绝对方法(Absolute):直接根据索引值来读取/写入数据,该形式不会影响posiiton的值。
下面以CharBuffer为例子:
CharBufferTest类 运行结果小提示:使用allocate创建的Buffer都是普通的Buffer,多用于生存期短,用完一次就扔掉。而ByteBuffer中提供了allocateDirect创建的Buffer,成本高,适用于生存期长,使得IO操作更快!
二、Channel
通道,顾名思义,与流不同的是(流只能进行单向读或写的操作,因为每一种流只能继承一种InputStream或OutputStream等基类),通道是双向的,即可以读或写亦可以同时读写的操作。不过我们不是直接通过对通道进行读与写的操作,而是使用缓冲区Buffer,即要Channel中读取数据,需要先用Buffer从Channel中取出一些数据,然后在从Buffer中来读取数据,反之向Channle中写入数据也是如此,先向Buffer中写入一些数据,然后程序使用Buffer向Channel写入数据。
Java中重要的一些通道的实现:
FileChannel:从文件中读写数据
DatagramChannel:通过UDP读写网络中的数据
SocketChannel:通过TCP读写网络中的数据
ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
下面以FileChannel作为例子:
注意:文件通道总是阻塞式的,即FileChannel是线程安全的,在一个线程对他的对象进行操作的时候,其他线程必须等待。
还有一点,当有2个通道,其中一个通道是FileChannel的时候,通道之间是可以传输数据的!通过FileChannel的两个方法:
transferFrom和transferTo"
三、编码集和Charset
我们都知道对于文件文本(图片、音频等暂且不谈),也就是字符这些我们肉眼都能够看懂,但是对于计算机,它只认识0和1,那该怎么办呢,于是便有了编码,就是将这些字符转化成一系列的二进制字节序列让计算机能够识别(不同的字符有着相应的二进制的字节序列),相反就有了解码,能够让我们看的懂(不费劲)。
同时,我们知道计算机是外国人发明的,由于使用的是英语,so使用英语的话不必考虑这些,但是发展是普及的,世界上这么多国家,每个国家的语言是不一样的,尤其是我们华夏之国,汉子那可不是区区26个字母能比的😋!于是经过人们不断地努力,一系列的字符集出现了。以下是我们国人常用的字符集提供编码与解码:
·GBK: 简体中文字符集。
·BIG5: 繁体中文字符集。
·ISO-8859-1: ISO拉丁字母表No.1,也叫做ISO-LATIN-1。
·UTF-8: 8位UCS转化格式。
·UTF-16BE: 16位UCS转换格式,BigEndian(最低位存放最高位字节)字节顺序。
·UTF-16LE: 16位UCS转换格式,LittleEndian(最高位存放最低位字节)字节顺序。
·UTF-16: 16位UCS转换格式,字节顺序由可选的字节顺序标记。
在Java中,提供了Charset供我们来进行编码和解码,用法如下:
→public static Charset forName(String charsetName):创建Charset对象,参数charsetName是相应字符集名称。
→public final ByteBuffer encode(CharBuffer cb):将CharBuffer中的字符序列转换成字节序列的便捷方法。
→public final ByteBuffer encode(String str):将String中的字符序列转换成字节序列的便捷方法。
→public final CharBuffer decode(ByteBuffer bb):将ByteBuffer中的字节序列转换成字符序列的便捷方法。
或者获取对象对应的编码器和解码器来进行操作:
调用Charset对象的newEncoder()返回一个CharsetEncoder对象(使用encode方法将字符序列转化成字节序列),或调用newDecoder()返回一个CharsetDecoder对象(使用decode方法将字节序列转化成字符序列)。下面以GBK编码集作为例子:
运行结果:
另外String类提供了getBytes(String charset)方法将字符序列转换成字节序列(使用特定的字符集,因平台而异);String类的构造器提供了将字节序列转字符序列的功能:new String(byte[] bytes,String encoding),
其本质是将其它编码集朝Unicode字符集转换,其中有涉及到兼容的问题。
网友评论