前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >总结了才知道,原来Java NIO的channel是这么用的!

总结了才知道,原来Java NIO的channel是这么用的!

作者头像
JavaEdge
发布2021-10-18 15:02:23
7110
发布2021-10-18 15:02:23
举报
文章被收录于专栏:JavaEdge

1 简介

Java NIO的Channel类似流,是用于传输数据的数据流,但有不同:

  • 既可从Channel读数据,也可写数据到Channel。但流的读写通常单向
  • Channel可异步读写
  • Channel中的数据总要先读到一个Buffer,或从一个Buffer中写入

从Channel读数据到缓冲区,从缓冲区写数据到Channel。

Channel(实现接口java.nio.channels.Channel的类)旨在提供往返NIO缓冲区的批量数据传输。这是与比较高级的I/O库(包java.io和java.net)的类并行存在的底层数据传输机制。可以从高级的数据传输类(例如java.io.File,java.net.ServerSocket或java.net.Socket)获得Channel实现,反之亦然。 Channel类似于在类似Unix的“文件描述符”。

与缓冲区不同,Channel不能被重复使用,一个打开的Channel即代表与一个特定I/O服务的特定连接,并封装该连接的状态。当Channel关闭时,那个连接会丢失,然后Channel将不再连接任何东西。

FileChannel(java.nio.channels.FileChannel)可以使用任意缓冲区,但也可以使用m-map建立直接映射到文件内容的缓冲区。它们还可以与文件系统锁进行交互。同样,SocketChannel(java.nio.channels.SocketChannel和java.nio.channels.ServerSocketChannel)允许在Socket和NIO缓冲区之间进行数据传输。

FileChannel可用于进行文件复制,这可能比对字节数组使用旧的读/写方式要有效得多。典型用法:

代码语言:javascript
复制
// 获得 file channels
try(FileChannel in = FileChannel.open(source, StandardOpenOption.READ);
    FileChannel out = FileChannel.open(target, StandardOpenOption.WRITE)
){
    // JavaVM does its best to do this as native I/O operations.
    in.transferTo(0, in.size(), out);
}

2 Channel的实现

Java NIO中最重要的Channel的实现:

  • FileChannel 从文件中读写数据
  • DatagramChannel 通过UDP读写网络中的数据
  • SocketChannel 通过TCP读写网络中的数据
  • ServerSocketChannel 监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel

3 API

3.1 read

read()表示该通道读就绪,可以从Channel中读取内容到缓冲区

3.2 wirte

表示该通道写就绪,可以将缓冲区中的内容写入Channel。

4 FileChannel

示例

使用FileChannel读数据到Buffer的示例:

代码语言:javascript
复制
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();

ByteBuffer buf = ByteBuffer.allocate(48);

int bytesRead = inChannel.read(buf);
while (bytesRead != -1) {
  System.out.println("Read " + bytesRead);
  buf.flip();

  while(buf.hasRemaining()){
      System.out.print((char) buf.get());
  }

  buf.clear();
  bytesRead = inChannel.read(buf);
}
aFile.close()

注意 buf.flip(),首先读取数据到Buffer,然后反转Buffer,接着再从Buffer中读取数据。

5 SocketChannel

API

read

返回值是一个int数据,代表此次有多少字节数据被写入Buffer。 若返回-1,说明Channel内数据已经读取完毕,到底了(连接关闭)。

向SocketChannel写数据

向SocketChannel中写入数据是通过write()方法,write也需要一个Buffer作为参数。下面看一下具体的示例:

代码语言:javascript
复制
ByteBuffer buf = ByteBuffer.allocate(48);

buf.clear();
buf.put("hello client".getBytes());
buf.flip();

while(buf.hasRemaining()) {
	// 该方法非阻塞,若此时无法写入也不会阻塞在此,而是直接返回 0 了
    channel.write(buf);
}

参考

  • http://tutorials.jenkov.com/java-nio/channels.html
  • https://en.wikipedia.org/wiki/Non-blocking_I/O_(Java)#Channels
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/05/18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 简介
  • 2 Channel的实现
  • 3 API
    • 3.1 read
      • 3.2 wirte
      • 4 FileChannel
        • 示例
        • 5 SocketChannel
          • API
            • read
          • 向SocketChannel写数据
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档