NIO基础入门(二)之通道Channel

[TOC]

1.概念

nio的第二个创新Channel,既不是扩展也不是增强,而是全新的与I/O服务的直接连接

Channel通常位于字节缓冲区和通道另一边的实体(文件/套接字等)之间有效的数据传输

通道两端为缓冲区,是通道发送接收数据的端点,假设为A/B

  1. A端:一个数据被填充到缓冲区中,接着将缓冲区中的数据冲到通道中–>到达通道B端

  2. B端:flip翻转缓冲区(打开盖子)并清空

与缓冲区不同,通道API主要由接口指定,不同的操作系统上的实现会有根本性差异

所以通道的API仅仅描述可以做什么

(实现经常使用操作系统的本地代码,通道接口允许以一种受控且可移植的方式来访问底层I/O服务)

通道的单/双向

通道可以是单向(unidirectional)或者双向的(bidirectional)

一个channel类实现ReadableByteChannel接口提供的read()方法

另一个channel类实现WritableByteChannel接口提供的write()方法

那么这两个管道都是单向的,

如果一个类同时实现这两个接口,那么他就是双向的,可以双向传输数据

2.Channel源码

1
2
3
4
public interface Channel extends Closeable {
public boolean isOpen();
public void close() throws IOException;
}

在顶级接口中,只有打开判断关闭通道两个方法,所有有趣的实现都在他的子接口和实现类中

大部分通道是可中断的,只要有实现InterruptibleChannel可中断接口

Channel接口引申出的其他接口都是面向字节的子接口,包括Writable ByteChannel和ReadableByteChannel等

通道只能在字节缓冲区上操作,层次结构表名其他类型的通道也可以从Channel接口引申,都是字节实现,因为操作系统都是以字节实现底层I/O接口的

3.类型

JDK1.4

文件通道:

FileChannel

套接字通道:

SocketChannel

ServerSocketChannel

DatagramChannel

JDK1.7以后完善AIO增加类型

nio2 增加回调

CompletionHandler

文件通道:

AsynchronousFileChannel 异步文件IO

套接字通道

AsynchronousSocketChannel 客户端

AsynchronousServerSocketChannel 服务器

4.通道操作

FileChannel对象只能通过一个打开的RamdomAccessFile/FileInputStream或者FileOutputStream对象上调用

getChannel()方法来获取,而不能直接创建一个FileChannel对象

建立连接

1
2
3
4
5
6
7
8
9
10
11
 SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("localhost",8000));

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress("localhost",8001));

DatagramChannel datagramChannel = DatagramChannel.open();
datagramChannel.connect(new InetSocketAddress("localhost",8002));

FileInputStream inputStream = new FileInputStream("d:\\test.txt");
FileChannel channel = inputStream.getChannel();

文件读写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
File src = new File("d:\\testdd.txt");
File target = new File("d:\\testddTarget.txt");
//if 判断略
FileInputStream fis = null;
FileOutputStream fos=null;
FileChannel cfis=null;
FileChannel cfos=null;
try {
fis = new FileInputStream(src);
fos = new FileOutputStream(target);
cfis = fis.getChannel();
cfos = fos.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
while (cfis.read(byteBuffer)>0){
byteBuffer.flip(); //注意,读写转换一定要翻转,否则写出去的是乱码或者空占位
cfos.write(byteBuffer);
byteBuffer.clear();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (cfis.isOpen()) //通道需要关闭,因为通道无法复用
cfis.close();
if (cfos.isOpen())
cfos.close();
fis.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("写出成功");

5.Channel矢量I/O

Scatter/Gather

简单而强大的概念,可以在多个缓冲区上实现一个简单的I/O操作

对于write而言:数据从几个缓冲区中按顺序抽取(gather)并沿着通道发送

对于read而言:从通道中读取的数据会按顺序散布(Scatter)到多个缓冲区,将每个缓冲区填满直至通道中的数据或者缓冲区最大空间消耗完

注意:缓冲区本身并不具备Scatter/Gather

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
File src = new File("d:\\testdd.txt");
File target = new File("d:\\testddTarget.txt");

FileInputStream fis = null;
FileOutputStream fos=null;
FileChannel cfis=null;
FileChannel cfos=null;
try {
fis = new FileInputStream(src);
fos = new FileOutputStream(target);
cfis = fis.getChannel();
cfos = fos.getChannel();
ByteBuffer byteBuffer1 = ByteBuffer.allocateDirect(1024);
ByteBuffer byteBuffer2 = ByteBuffer.allocateDirect(1024*16);


ByteBuffer[] byteBuffers={byteBuffer1,byteBuffer2}; //合并

while (cfis.read(byteBuffers)>0){ //Scatter注入
byteBuffer1.flip();
byteBuffer2.flip();
cfos.write(byteBuffers); //gather抽取
byteBuffer1.clear();
byteBuffer2.clear();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (cfis.isOpen())
cfis.close();
if (cfos.isOpen())
cfos.close();
fis.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("写出成功");

6.文件通道

对于文件通道来说,总司阻塞式的,因此不能被置于非阻塞模式(由文件I/O性质决定)

对于文件I/O而言,最强大之处在于异步I/O,他可以允许一个进程操作一个或多个I/O操作,即AIO

FileChannel对象是线程安全的,多个进程(进程级别和线程)可以在同一个实例(磁盘文件)上并发调用方法而不会有任何问题

但是影响通道位置和大小的操作都是单线程,这些操作同时最多只有一个执行,再多尝试会产生阻塞

IO VS NIO1 VS NIO2

https://www.jianshu.com/p/1e55c6705392