文章目录
NIO概述
Java NIO(New IO 或 Non Blocking IO)是从 Java 1.4 版本开始引入的一个新的IO API,可以替代标准的 Java IO API。NIO 支持面向缓冲区的、基于通道的 IO 操作。NIO 将以更加高效的方式进行文件的读写操作。
Java NIO有三大核心组件:Channel、Buffer和Selectors。
1、Channel是什么?
Channel可译为“通道”,Channel 和 IO 中的Stream(流)是差不多一个等级的。只不过 Stream 是单向的,而Channel是全双工的,通过缓冲区Buffer来进行读写操作。 NIO 中的 Channel 的主要实现有:FileChannel、DatagramChannel、SocketChannel 和 ServerSocketChannel,分别可以对应文件 IO、UDP 和 TCP(Server 和 Client)。2、Channel的主要实现
2.1 FileChannel
FileChannel 顾名思义是从文件中读写数据的Channel。
(1)借助RandomAccessFile创建一个FileChannel String fileName = "e://001.txt";//文件路径
RandomAccessFile aFile =
new RandomAccessFile(fileName,"rw");
FileChannel channel = aFile.getChannel();
(2)Channel必须借助缓冲区来进行数据交换,因此需要创建一个Buffer
ByteBuffer buf = ByteBuffer.allocate(1024);
//读数据到buffer中
int bytesRead = channel.read(buf);
(3)进行读写操作
while(bytesRead != -1){
System.out.println("读取了"+bytesRead);
buf.flip();//调用buffer反转读写模式
while(buf.hasRemaining()){//如果buffer中还有剩余
System.out.println((char) buf.get());
}
buf.clear();//清除缓冲区内容
bytesRead = channel.read(buf);
}
//aFile.close();
System.out.println("读数据结束!");
//向FileChannel中写数据
if(buf.hasRemaining()) buf.clear();
String a = "hello Java NIO!";
//向缓冲区写入数据
buf.put(a.getBytes());
buf.flip();
//最后由FileChannel将缓冲区的数据写入
while(buf.hasRemaining()){
channel.write(buf);
}
channel.close();
System.out.println("写数据完成!");
2.2 ServerSocketChannel
ServerSocketChannel 是一个基于通道的 socket 监听器。它同我们所熟悉的java.net.ServerSocket 执行相同的任务,不过它增加了通道语义,因此能够在非阻塞模式下运行。
ByteBuffer byteBuffer = ByteBuffer.wrap("Hello java nio!".getBytes());
ServerSocketChannel ssc = ServerSocketChannel.open();
//取出对等的 socket,绑定到一个端口进行监听
ssc.socket().bind(new InetSocketAddress(port));
//设置非阻塞模式
ssc.configureBlocking(false);
2.3 SocketChannel
(1)创建一个SocketChannel
SocketChannel socketChannel = SocketChannel.open(
new InetSocketAddress("www.baidu.com", 80));
(2)连接校验
socketChannel.isOpen(); // 测试 SocketChannel 是否为 open 状态
socketChannel.isConnected(); //测试 SocketChannel 是否已经被连接
socketChannel.isConnectionPending(); //测试 SocketChannel 是否正在进行连接
socketChannel.finishConnect(); //校验正在进行套接字连接的 SocketChannel是否已经完成连接
(2)读写
SocketChannel socketChannel = SocketChannel.open(
new InetSocketAddress("www.baidu.com", 80));
socketChannel.configureBlocking(false);//设置 SocketChannel 的读写模式非阻塞
ByteBuffer byteBuffer = ByteBuffer.allocate(16);
socketChannel.read(byteBuffer);
socketChannel.close();
System.out.println("read over");
2.4 DatagramChannel
DatagramChannel 是无连接的,每个数据报(datagram)都是一个自包含的实体,拥有它自己的目的地址及不依赖其他数据报的数据负载。与面向流的的 socket 不同,DatagramChannel 可以发送单独的数据报给不同的目的地址。同样,DatagramChannel 对象也可以接收来自任意地址的数据包。每个到达的数据报都含有关于它来自何处的信息(源地址)。 代码示例:@Test
public void sendDatagram() throws IOException, InterruptedException {
DatagramChannel sendChannel= DatagramChannel.open();
InetSocketAddress sendAddress= new InetSocketAddress("127.0.0.1", 9999);
while (true) {
sendChannel.send(ByteBuffer.wrap("发包".getBytes("UTF-8")), sendAddress);
System.out.println("发包端发包");
Thread.sleep(1000);
}
}