FileChannel
- 打开 FileChannel,需要通过 InputStream、OutputStream 或 RandomAccessFile 来获取一个 FileChannel 实例
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
- 从 FileChannel 读取数据,需要分配一个 Buffer,在将 FileChannel 中的数据读到 Buffer 中
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
String str = "abc";
ByteBuffer byteBuffer = ByteBuffer.allocate(48);
byteBuffer.put(str.getBytes());
byteBuffer.flip();
while (byteBuffer.hasRemaining()) {
fileChannel.write(byteBuffer);
}
channel.close();
- 若需要在特定位置进行数据读/写操作可以调用 position() 方法获取 FileChannel 当前位置,也可以设置当前位置(注意:如果将位置设置在文件结束符之后,然后在向通道写数据,文件将撑大到当前位置并写入数据,这可能导致"文件空洞")
long pos = channel.position();
channel.position(pos +123);
long fileSize = channel.size();
- 使用 truncate() 方法截取一个文件,截取文件时文件中指定长度后面的部分将被删除
channel.truncate(1024);
- force() 方法将通道里尚未写入磁盘的数据强制写到磁盘上,出于性能方面考虑,操作系统将数据缓存在内存中,无法保证写入到 FileChannel 里的数据一定会即时写到磁盘上,force() 方法有一个 boolean 类型的参数,指明是否同时将文件元数据(权限信息等)写到磁盘上
channel.force(true);
通道间的数据传输
- FileChannel 的 transferFrom() 方法可以将数据从源通道传输到 FileChannel 中
try (RandomAccessFile raf = new RandomAccessFile("/Users/linyuan/Documents/字目录.txt", "rw");
RandomAccessFile toFile = new RandomAccessFile("/Users/linyuan/Documents/toFile.txt", "rw")) {
FileChannel fromChannel = raf.getChannel();
FileChannel toChannel = toFile.getChannel();
long position = 0;
long count = fromChannel.size();
// position 表示从 position 处开始向目标文件写入数据,count 表示最多传输的字节数
// 如果源通道的剩余空间小于 count 个字节,则所传输的字节数要小于请求的字节数
toChannel.transferFrom(fromChannel, position, count);
} catch (Exception e) {
e.printStackTrace();
}
- transferTo() 方法将数据从 FileChannel 传输到其他的 channel 中
SocketChannel
- SocketChannel 是一个连接到 TCP 网络套接字的通道
- 通过 SocketChannel 的 open() 创建 SocketChannel 实例,并通过 connect() 连接服务器
socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1", 80));
非阻塞模式
- 此时调用 connect 方法可能在建立连接前就返回了,为了确定是否建立连接,可以调用 finishConnect 方法
socketChannel.configureBlocking(false); // 设置为非阻塞模式
socketChannel.connect(new InetSocketAddress("http://www.baidu.com", 80));
while(!socketChannel.finishConnect() ){
//wait, or do something else...
}
ServerSocketChannel
- ServerSocketChannel 是一个服务器端 SocketChannel,监听 TCP 连接通道
- 通过 ServerSocketChannel 的 open() 创建 ServerSocketChannel 实例,并绑定端口
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9999));
- 循环调用 accept() 等待客户端连接,该方法默认为阻塞状态
while(true){
SocketChannel socketChannel =serverSocketChannel.accept();
//do something with socketChannel...
}
非阻塞模式
- 在非阻塞模式下 accept 方法会立即返回,如果没有新客户端连接,则返回值为 null,需要检查 SocketChannel 是否为 null
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false); // 设置为非阻塞模式
while(true){
SocketChannel socketChannel = serverSocketChannel.accept();
if(socketChannel != null){
//do something with socketChannel...
}
}
DatagramChannel
- DatagramChannel 是一个能收发 UDP 数据包的通道,因为 UDP 是无连接的网络,所以不能像其它通道一样读取和写入,只能发送和接收数据包
- 通过 DatagramChannel 的open() 创建 DatagramChannel 实例,并绑定端口
DatagramChannel channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(9999));
ByteBuffer buf = ByteBuffer.allocate(48);
channel.receive(buf);
String str = "新的一天";
ByteBuffer buf = ByteBuffer.allocate(48);
buf.put(str.getBytes());
buf.flip();
channel.send(buf, new InetSocketAddress("localhost", 9999));
连接到特定的地址
- DatagramChannel 可以“连接”到网络中特定地址,通过 connect 方法,但这种连接并非真正的连接,而是锁住发送的地址,让其只能从特定地址收发数据
channel.connect(new InetSocketAddress("localhost", 80));
int bytesRead = channel.read(buf);
int bytesWritten = channel.write(but);
网友评论