DatagramChannel
channel 分类FileChannel: 主要用于文件的读写,可以从磁盘上读取文件,也可以向磁盘上写入文件。
SocketChannel:用于 Socket 的 TCP 连接的数据读写,既可以从 Channel 读数据,也可以向 Channle 中写入数据
ServerSocketChannel:通过 ServerSocketChannel 可以监听 TCP 连接,服务端监听到连接之后,会为每个请求创建一个 SocketChannel
DatagramChannel:用于 UDP 协议的数据读写
接下来就分别介绍一下。
FileChannel主要用于操作文件,废话不多说,直接看例子。
准备文件 test-file.txt ,内容 shDEQuanZhanBiJi
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 的熟悉程度了,算是埋的一个坑。
如果不知道为啥文件是空的,可以去看看上面讲 ByteBuffer 的文章,接下来是解答。
这是因为我们创建一个 ByteBuffer 的时候默认是处于写模式的,此时如果去通过 position 和 limit 去读取数据是读不到的。所以在调用 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();
}
可以看到,文件生成了,内容也有了:
但是呢,上面将的两种要么只能写,要么只能读。例如 FileInputStream 如果你硬要往 channel 里怼数据,程序最后会抛出 NonWritableChannelException 异常,告诉你这玩意儿写不了。
那有没有一个既能写,又能读还能唱跳的实现呢?当然有,那就是 RandomAccessFile。