1、NIO
JDK1.4出现的新的IO (New IO) API
有三个重要的组成部分:
缓冲区(Buffer)、通道(Channel)、选择器(Selector)
缓冲区用于存储数据,通道用于传输数据,选择器用于监控数据
2、Buffer(缓冲区)
⑴ 一个用于特定基本数据类型的容器
一共有7种(除了boolean类型):
ByteBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
CharBuffer
⑵ 属性
limit 限制,第一个不应该读取或写入的元素的索引。不能为负数,且不能大于其容量
position 位置,下一个要读取或写入的元素的索引。不能为负数,且不能大于其容量
capacity 容量,缓冲区包含的元素的数量。不能为负数,且一旦指定后将不能更改
⑶ mark、limit、position、capacity
0 <= mark <= limit <= position <= capacity
⑷ API
⒈ allocate
public static ByteBuffer allocate(int capacity) {}
静态方法,以ByteBuffer为例,创建非直接缓冲区
⒉ allocateDirect
public static ByteBuffer allocateDirect(int capacity) {}
静态方法,以ByteBuffer为例,创建直接缓冲区
Tips:如果创建了直接缓冲区,则JVM会尽最大努力直接在此缓冲区上进行I/O操作,会尽量避免将缓冲区的内容复制到中间缓存区中
注意:建议将直接缓冲区主要分配给那些易受基础系统的本机I/O操作影响的大型的、持久的缓冲区。一般仅在使用直接缓冲区能给程序性能方面带来明显好处时分配
⒊ flip
切换为读取数据模式
⒋ rewind
可以重复读取数据
⒌ clear
清空缓冲区,limit变为capacity大小(不能操作的索引位置),position变为0(下一个可以操作的位置)。但是里面的数据还存在
⒍ mark
标记position位置(下一个可以操作的索引位置)
⒎ reset
回退到mark标记的position位置
3、Channel(通道)
⑴ 用于源节点和目标节点的连接
在NIO中负责数据的传输。它本身不存储数据,需要配合缓冲区来使用
⑵有四个主要的实现类
FileChannel
SocketChannel
ServerSocketChannel
DatagramChannel
⑶ 获取方式
⒈ 方式一
FileInputStream 或 FileOutputStream 或 RandomAccessFile 的getChannel方法
Socket 或 ServeSocket 或 DatagramSocket的getChannel方法
⒉ 方式二【JDK7】
对应类型的静态的open方法
public static FileChannel open(Path path, OpenOption… options) {}
第一个参数为路径,通过Paths.get(“”)方法来获取文件路径。之后是可变参数,使用StandardOpenOption枚举类来指定是读、写还是其他
public static Path get(String first, String… more) {}
获取路径
StandardOpenOption.READ 读模式
StandardOpenOption.WRITE 写模式
StandardOpenOption.CREATE_NEW 创建新文件(如果文件已经存在,再次创建时会报错)
StandardOpenOption.CREATE 覆盖文件
3.方式三【JDK7】
Files.newByteChannel方法
⑷ 直接缓冲区
MappedByteBuffer 通过FileChannel的map方法获取
MappedByteBuffer map(MapMode mode, long position, long size)
第一个参数是映射的模式,通过MapMode的常量来指定是只读还是读写;第二个参数是起始位置(从0开始);第三个参数是要映射的区域大小,通过FileChannel的size方法获取【注意是读取通道】
相关方法:
⒈ get
public ByteBuffer get(byte[] dst) {}
将直接缓冲区中读取到的数据放到byte数组中
⒉ put
public final ByteBuffer put(byte[] src) {}
将字节数据中的数据输出到缓冲区中
⑸ Channel的API
⒈ transferTo
long transferTo(long position, long count, WritableByteChannel target) {}
将可读通道中的数据传输给指定的可写通道。返回实际传输的字节大小,可能为0【通过读取通道调用】
⒉ transferFrom
long transferFrom(ReadableByteChannel src, long position, long count)
将指定的可读通道中的数据传输给此可写通道。返回实际传输的字节大小,可能为0【通过写出通道调用】
⒊ read(ByteBuffer[] dsts)
分散读取
⒋ write(ByteBuffer[] srcs)
聚集写入。注意:写入前,需要将所有的缓冲区开启读取模式(遍历调用flip方法)
4、字符缓冲区(CharBuffer)
⑴ 字符对象、字符编码器和解码器
⒈ Charset.forName(“编码集”)
获取指定编码集的Charset对象
⒉ 获取编码器和解码器
调用Charset对象的
CharsetEncoder newEncoder();
CharsetDecoder newDecoder();
方法
⒊ 编码
调用CharsetEncoder的encode方法
ByteBuffer encode(CharBuffer in) {}
⒋ 解码
调用CharsetDecoder的decode方法
CharBuffer decode(ByteBuffer in) {}
⑵ 示例
Charset charset = Charset.forName("UTF-8");
CharsetEncoder encoder = charset.newEncoder();
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = CharBuffer.allocate(1024);
charBuffer.put("你好!");
charBuffer.flip();
try {
ByteBuffer byteBuffer = encoder.encode(charBuffer);
CharBuffer buffer = decoder.decode(byteBuffer);
System.out.println(buffer);
} catch (CharacterCodingException e) {
e.printStackTrace();
}