Java NIO Channel 使用

DatagramChannel

channel 分类

channel 分类

FileChannel: 主要用于文件的读写,可以从磁盘上读取文件,也可以向磁盘上写入文件。

SocketChannel:用于 Socket 的 TCP 连接的数据读写,既可以从 Channel 读数据,也可以向 Channle 中写入数据

ServerSocketChannel:通过 ServerSocketChannel 可以监听 TCP 连接,服务端监听到连接之后,会为每个请求创建一个 SocketChannel

DatagramChannel:用于 UDP 协议的数据读写

接下来就分别介绍一下。

FileChannel

主要用于操作文件,废话不多说,直接看例子。

准备文件 test-file.txt ,内容 shDEQuanZhanBiJi

test-file.txt 文件

test-file.txt 文件 输入 FileInputStream

用于从 FileChannel 中读取数据,例如将指定文件输入到 FileChannel 中,我们就能获取到文件的内容,接下来编写 FileChannel 的 输入流 核心代码:

public static void main(String[] args) throws IOException {
  // 创建一个输入流
  FileInputStream fileInputStream = new FileInputStream("test-file.txt");
  // 通过输入流获取到 channel
  FileChannel fileChannel = fileInputStream.getChannel();

  // 准备好 ByteBuffer
  ByteBuffer buffer = ByteBuffer.allocate(16);
  // 将 输入流 的 channel 的数据读入 buffer 中
  fileChannel.read(buffer);

  // 简单打印 buffer 的内容
  printBuffer(buffer); // shDEQuanZhanBiJi
}

这里面的 ByteBuffer 是 channel 进行读、写数据的中间媒介。要从 channel 中读取数据(也就是上面这个例子),需要先将数据读到 ByteBuffer 中;同理,要想向 channel 中写入数据,也需要先将数据写入 ByteBuffer(下面讲输出流的时候会讲)。

对 ByteBuffer 不熟悉的可以先看看我之前写的《玩转 ByteBuffer》,printBuffer 的代码里面也有

输出 FileOutputStream

顾名思义,是 FileChannel 要向外输出数据,例如将数据写入到磁盘文件上,接下来通过例子看看效果:

public static void main(String[] args) throws IOException {
  // 指定需要生成的文件名称
  String generateFileName = "generate-file.txt";
  // 创建一个输出流
  FileOutputStream fileOutputStream = new FileOutputStream(generateFileName);
  // 通过输出流获取到 channel
  FileChannel fileChannel = fileOutputStream.getChannel();

  // 准备好 ByteBuffer, 并向里面写入数据
  ByteBuffer buffer = ByteBuffer.allocate(16);
  buffer.put("shDEQuanZhanBiJi".getBytes(StandardCharsets.UTF_8));

  // 将 输入流 的 channel 的数据读入 buffer 中
  fileChannel.write(buffer);
  fileChannel.close();
}

相应的注释都已经贴在对应的代码上了,细节在此不再赘述。唯一需要关注的是,调用 write 写文件到磁盘上时,也是先传入的 ByteBuffer。

好了,当你运行完代码你会发现,虽然文件是生成的了,但是里面却是空白的...这其实就涉及到对 ByteBuffer 的熟悉程度了,算是埋的一个坑。

Java NIO Channel 使用

如果不知道为啥文件是空的,可以去看看上面讲 ByteBuffer 的文章,接下来是解答。

这是因为我们创建一个 ByteBuffer 的时候默认是处于写模式的,此时如果去通过 positionlimit 去读取数据是读不到的。所以在调用 write 之前,我们需要先将 ByteBuffer 切换到读模式,完整代码如下:

public static void main(String[] args) throws IOException {
  // 指定需要生成的文件名称
  String generateFileName = "generate-file.txt";
  // 创建一个输出流
  FileOutputStream fileOutputStream = new FileOutputStream(generateFileName);
  // 通过输出流获取到 channel
  FileChannel fileChannel = fileOutputStream.getChannel();

  // 准备好 ByteBuffer, 并向里面写入数据
  ByteBuffer buffer = ByteBuffer.allocate(16);
  buffer.put("shDEQuanZhanBiJi".getBytes(StandardCharsets.UTF_8));

  // 将 ByteBuffer 切换到读模式
  buffer.flip();
  // 将 输入流 的 channel 的数据读入 buffer 中
  fileChannel.write(buffer);
  
  fileChannel.close();
}

可以看到,文件生成了,内容也有了:

Java NIO Channel 使用

但是呢,上面将的两种要么只能写,要么只能读。例如 FileInputStream 如果你硬要往 channel 里怼数据,程序最后会抛出 NonWritableChannelException 异常,告诉你这玩意儿写不了。

Java NIO Channel 使用

那有没有一个既能写,又能读还能唱跳的实现呢?当然有,那就是 RandomAccessFile。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzwdss.html