1 java NIO概述
NIO和BIO有着相同的目的,都是用于进行输入/输出,但NIO使用了不同的方式来处理输入/输出。NIO采用内存映射文件的方式来处理输入/输出,NIO将文件或者文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件了,通过这种方式来进行输入/输出比BIO的方式输入/输出要快得多。
java中与NIO相关的主要类组成元素有 Buffer, Channel, Selector.
Buffer可以理解为一个容器,它的本质是一个数组,发送到Channel中的所有对象都必须首先放到Buffer中,而从Channel中读取的数据也必须先放到Buffer中。
Channel是对传统的输入/输出系统的模拟,NIO中的数据都是通过Channel传输; Channel与传统的InputStream,OutputStream最大的区别在于它提供了一个map()方法,通过该map()方法可以直接将“一块数据”映射到内存当中。如果说传统的输入/输出系统是面向流处理,则NIO则是面向块处理。
1.1 Buffer的使用
Buffer是一个抽象类,其最常用的子类是ByteBuffer,它可以在底层字节数组上进行get/set操作。除了ByteBuffer之外,对应于其他基本数据类型都有相应的Buffer类.这些子 类也都没有构造器。
static XxxBuffer allocate(int capacity) : 创建一个容量为capacity的XxxBuffer对象。使用较多的一般是ByteBuffer和CharBuffer。
在Buffer中有三个重要的概念:容量(capacity),界限(limit), 位置(position)。
容量(capacity): 缓冲区的容量表示该Buffer最大的数据容量,即最多可以存储多少数据。值不可以为负数,一旦创建之后不可以更改。
界限(limit) : 第一个不可被读/写的数据缓冲区的位置索引,也就是说limit后的数据不可被读和写。
位置(position) : 用于指明下一个可以被读出的或者写入的缓冲区位置索引。
Buffer中常用方法:
int capacity() : 返回Buffer的容量大小。
boolean hasRemaining() : 判断当前位置和界限之间是否还有元素可供处理。
int limit() : 返回Buffer的界限位置。
Buffer limit(int newlt) : 重新设置界限的值,并返回一个具有新的limit的缓冲区对象。
Buffer mark() : 设置Buffer的mark位置, 它只能在0和位置之间做mark.
int position() : 返回Buffer中的position位置。
Buffer position(int newPs) : 设置Buffer的position, 并返回position被修改后的Buffer对象。
int remaining() : 返回当前的位置和界限之间元素的个数。
Buffer reset() : 将位置转到mark所在的位置。
Buffer rewind() : 将位置设置成0, 取消设置的mark.
void put() : 向Buffer中存放一些数据。
void flip() : 将limit设置到position的位置
void clear() : 将position置为0,将limit置为capacity, 这样为再次向Buffer中装入数据做好准备。
Buffer中读入一些数据后的示意图如下:
1.2 使用Channel
Channel类似于传统的流对象,当时与传统的流对象有两个主要的区别,
Channel可以直接将指定文件的部分或全部直接映射成Buffer。
程序不能直接通过访问Channel中的数据,包括读和写都不行,Channel只能与Buffer进行交互。所有的Channel都不应该通过构造器来直接创建。而是通过传统的节点 InputStream, OutputStream的getChannel()方法来返回对应的Channel,不同的节点流获得的Channel不一样。如:FileInputStream,FileOutputStream getChannel()返回 的是FileChannel, PipedInputStream和PipedOutputStream的getChannel()的方法返回的是Pipe.SinkChannel和Pipe.SourceChannel。
channel的常用方法有
map() : 用于将channel的部分或者全部数据映射成对应的Buffer。
read() : 从Buffer中读数据。
write() : 从Buffer中写数据。
1.3 文件锁
FileChannel中提供了lock()/tryLock()方法可以获得文件锁FileLock对象,从而锁定文件,方法如: lock() 如果无法得到文件锁,程序将一直阻塞,tryLock()是尝试锁定文 件,它将直接返回而不是阻塞,如果获取到了文件锁,将返回文件锁,否则返回null。
lock(long position, long size, boolean shared) : 对文件从position的位置开始长度为size的内容加锁, 第3个参数是设置是共享锁还是排他锁。该方法是阻塞试方法
tryLock(long position, long size, boolean shared) : 对文件从position的位置开始长度为size的内容加锁, 第3个参数是设置是共享锁还是排他锁。该方法是非阻塞试方法