一、NIO概述
- IO是阻塞的,NIO是非阻塞式的
- IO是面向流的(一次处理一字节,效率不高),NIO是面向块的
- IO是单线程的,NIO 是通过选择器来模拟多线程的
NIO在基础的IO流上发展处新的特点,分别是:内存映射技术,字符及编码,非阻塞I/O和文件锁定。
Channel(通道)和Buffer(缓冲)是NIO中的两个核心对象。
- Channel类似于传统IO中的流对象,其与InputStream和OutputStream最大的区别在于它提供了一个map()方法,通过该map()实现将一块数据直接映射到内存道中。
- Buffer可被理解为一个容器,本质是一个数组,发送到Channel中的对象和从Channel中读取数据时都必须先放到Buffer中。
二、Buffer
这些Buffer类都不提供构造器,而是通过static XxxBuffer allocate(int capacity)
来创建一个Buffer对象。Buffer有三个重要的概念:
- 容量(capacity):缓冲区容量大小,表示该Buffer最大数据容量。创建后不可改变。
- 界限(limit):第一个不该被读出或写入的缓冲区位置索引。
- 位置(position):用于指明下一个可被读出或写入的缓冲区位置索引。
当Buffer装入数据结束后,调用flip(),将limit设置为position所在位置,将position设置为0。
当数据输出结束后,调用clear(),将limit置为position,将position值为0,并不清除Buffer中的原有数据。
可通过put()、get()方法向Buffer中存、取数据。
三、Channel
-
所有的Channel都是通过传统节点流的
getChannel()
获得 -
Channel类似于传统的流对象,但二者的区别在于:
- Channel可以直接将指定的文件部分或全部直接映射成Buffer。
- 程序不能直接访问Channel中的数据(无论读、写),Channel只能与Buffer进行交互。
-
map()方法:该方法用于将Channel中对应的部分映射成ByteBuffer
MappedByteBuffer map(MapMode mode, long position, long size)
四、字符集Charset
- 字符集用于解决二进制序列与字符之间的映射关系
- Charset对象的获取方法
Charset charset = Charset.forName("GBK");
- 获取到Charset对象后,可调用此对象的newDecoder()、newEncoder()这两个方法分别获得该字符集的解码器和编码器。
五、Java7的NIO.2
- 提供了Path类,优化了传统File类功能有限且所提供方法性能不高的缺陷。
- 提供了Files和Paths两个工具类
- 使用FileVisitor遍历文件和目录
public interface FileVisitor<T> {
//访问子目录之前触发事件
FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
throws IOException;
//访问file文件时触发事件
FileVisitResult visitFile(T file, BasicFileAttributes attrs)
throws IOException;
//访问文件失败时触发事件
FileVisitResult visitFileFailed(T file, IOException exc)
throws IOException;
//访问子目录之后触发事件
FileVisitResult postVisitDirectory(T dir, IOException exc)
throws IOException;
}
以上四个方法都返回一个FileVisitResult对象,他是一个枚举类,代表后续行为
public enum FileVisitResult {
//继续访问
CONTINUE,
//中止范围跟
TERMINATE,
//继续访问,但不访问该文件或跳过该目录的子目录树
SKIP_SUBTREE,
//继续访问,但不访问该文件或目录的兄弟文件或目录
SKIP_SIBLINGS;
}
- 使用WatchService来监控文件变化
NIO.2的Path类提供如下方法来监听文件系统的变化
//用watcher监听变化。events参数指定要监听哪些类型的事件。
WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events)throws IOException;
WatchKey register(WatchService watcher,WatchEvent.Kind<?>[] events,WatchEvent.Modifier... modifiers)
throws IOException;
注册完成后,可调用WatchService的如下三个方法来获取变化事件
//获取下一个WatchKey,如果没发生,则返回null
WatchKey poll();
//等待指定的时间,返回下一个WatchKey,如果一直没事件发生则返回null
WatchKey poll(long timeout, TimeUnit unit) throws InterruptedException;
//获取下一个WatchKey,如果没发生就一直等待
WatchKey take() throws InterruptedException;