Java NIO
- Channels通道(连接)
- FileChannel
- DatagramChannel
- SocketChannel
- ServerSocketChannel
- Pipe.SinkChannel
- Pipe.SourceChannel
- Buffers缓冲区
- ByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- LongBuffer
- IntBuffer
- ShortBuffer
- MappedByteBuffer
- Selectors
- Pipe(管道)
FileChannel
FileChannel是一个连接到文件的通道。可以通过文件通道读写文件。
FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下。
在Java NIO中,如果两个通道中有一个是FileChannel,那你可以直接将数据从一个channel(译者注:channel中文常译作通道)传输到另外一个channel。
FileChannel的基本用法
1
2
3
4
5
6
7
8
9
10
11
12
13RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel(); //获取FileChannel
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf); //读取FileChannel中数据至ByteBuffer
long pos = inChannel.position(); //获取FileChannel的当前位置
inChannel.position(0); //设置FileChannel的当前位置,在此位置之后进行读或写
buf.flip(); //ByteBuffer从写模式转到读模式
inChannel.write(buf);//再将ByteBuffer中数据写入FileChannel
long fileSize = inChannel.size(); //返回此通道的文件的当前大小
inChannel.truncate(fileSize / 2); //截取文件
inChannel.force(true); //强制数据写入磁盘,参数表示是否同时将文件元数据(权限信息等)写到磁盘上。
inChannel.close(); //关闭transferFrom()
FileChannel的transferFrom()方法可以将数据从源通道传输到FileChannel中(译者注:这个方法在JDK文档中的解释为将字节从给定的可读取字节通道传输到此通道的文件中)。
1
2
3
4
5
6
7
8
9RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
FileChannel fromChannel = fromFile.getChannel();
RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
FileChannel toChannel = toFile.getChannel();
long position = 0;
long count = fromChannel.size();
toChannel.transferFrom(fromChannel, position, count);此外要注意,在SoketChannel的实现中,SocketChannel只会传输此刻准备好的数据(可能不足count字节)。因此,SocketChannel可能不会将请求的所有数据(count个字节)全部传输到FileChannel中。
transferTo()
transferTo()方法将数据从FileChannel传输到其他的channel中。
1
2
3
4
5
6
7
8
9RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
FileChannel fromChannel = formFile.getChannel();
RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
FileChannel toChannel = toFile.getChannel();
long position = 0;
long count= fromChannel.size();
fromChannel.transferTo(position, count, toChannel);
SocketChannel
Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道。可以通过以下2种方式创建SocketChannel:
- 打开一个SocketChannel并连接到互联网上的某台服务器。
- 一个新连接到达ServerSocketChannel时,会创建一个SocketChannel。
SocketChannel基本用法
1
2
3
4
5
6
7
8
9
10
11//通过调用系统级默认 SelectorProvider 对象的 openSocketChannel 方法来创建新的通道。
SocketChannel socketChannel = SocketChannel.open(); //打开套接字通道
//如果通道处于非阻塞模式,则发起一个非阻塞连接操作。如果立即建立连接(使用本地连接时就是如此),则返回true。否则此方法返回 false,并且必须在以后通过调用 finishConnect 方法来完成该连接操作。
boolean isConnectNow = socketChannel.connect(new InetSocketAddress("www.baidu.com"), 80); //连接到某个套接字
if(!isConnectNow) {
socketChannel.finishConnect();
}
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = socketChannel.read(buf);//从SocketChannel读取数据到ByteBuffer
buf.flip();//反转ByteBuffer,此时limit=position,postion=0,一般与compact()配合使用
socketChannel.write(buf); //写入SocketChannel;SocketChannel非阻塞模式
非阻塞模式与选择器搭配会工作的更好,通过将一或多个SocketChannel注册到Selector,可以询问选择器哪个通道已经准备好了读取,写入等。
1
2
3
4
5
6
7
8
9
10
11socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://baidu.com"), 80);
while(!socketChannel.finishConnect()) {
//waitting for connecting...
}
ByteBuffer buf = ByteBuffer.allocate(48);
socketChannel.read(buf);
while(buf.hasRemaing()) {
socketChannel.write(buf);
}
ServerSocketChannel
针对面向流的侦听套接字的可选择通道。
ServerSocketChannel基本用法
1
2
3
4
5
6
7
8
9
10
11
12ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false); //非阻塞模式
while(true) {
SocketChannel socketChannel = serverSocketChannel.accept();
//...
if(socketChannel != null) {
}
}
serverSocketChannel.close();
DatagramChannel
Java NIO中的DatagramChannel是一个能收发UDP包的通道。因为UDP是无连接的网络协议,所以不能像其它通道那样读取和写入。它发送和接收的是数据包。
DatagramChannel基本用法
1
2
3
4
5
6
7
8
9
10
11
12
13DatagramChannel channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(9999));
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
channel.receive(buf); //接收数据,如果buf大小不够,则会被丢弃
buf.flip();
int bytesSend = channel.send(buf, new InetSocketAddress("baidu.com", 80)); //发送数据
//连接到特定的地址,让其只能从特定地址收发数据,减少安全检查开销
channel.connect(new InetSocketAddress("baidu.com", 80));
int bytesRead = channel.read(buf);
int bytesWritten = channel.write(buf);