【ky开元棋盘网址】
一篇学会 Java NIO Channel 的运用
发布日期:2022-08-06 21:59    点击次数:70

本文转载自微信群众号「SH的全栈笔记」,作者SH的全栈笔记。转载本文请联络SH的全栈笔记群众号。

Java NIO 中的 Channel 分类:

FileChannel SocketChannel ServerSocketChannel 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。

这里提一嘴,调用完 write 着实不是登时就写入磁盘,也可以在操作体系的缓存里。假定需求登时刷盘,下载中心则调用 channel.force(true); 即可。

RandomAccessFile

怎么用的呢?着实跟班前两个差不多:

public static void main(String[] args) throws IOException {   // 指定需求生成的文件名称   String targetFileName = "target-file.txt";   // 创立 RandomAccessFile, 赋予可读(r)、可写(w)的权限   RandomAccessFile accessFile = new RandomAccessFile(targetFileName, "rw");   FileChannel fileChannel = accessFile.getChannel();    // 创立 ByteBuffer 并写入数据   ByteBuffer buffer = ByteBuffer.allocate(16);   buffer.put("shDEQuanZhanBiJi".getBytes(StandardCharsets.UTF_8));   // 切换到 buffer 的读情势   buffer.flip();   // 调用 write 将 buffer 的数据写入到 channel, channel 再写数据到磁盘文件   fileChannel.write(buffer);    // 相当于清空 buffer   buffer.clear();   // 将从前写入到 channel 的数据再读入到 buffer   fileChannel.read(buffer);    // 打印 buffer 中的内容   printBuffer(buffer);    fileChannel.close(); } 

运行当前的结果就是,会生成一个名为 target-file.txt 的文件,内容就是 shDEQuanZhanBiJi。并且掌握台会将从前写入 channel 的 shDEQuanZhanBiJi 打印进去。

老端方,细节都在注释中。值得留心的是 new RandomAccessFile(targetFileName, "rw"); 里的 rw 。注释里也写了,代表赋予可读、可写的权限。

再值得留心的是,你不克不迭说把 rw 改为 w。

不克不迭这么玩,因为它就是一个纯真的字符串成家,可供抉择的就这么些:

mode 范例

可以或许看到,r 必不成少...: r 只能读 rw 既能读,也能写

rws 和 rwd 功用和 rw 大致是沟通的,可读、可写。仅有不同是他们会将每次篡改强逼刷到磁盘,并且 rws 会将操作体系对该文件的元数据也一起刷盘,发挥阐发就是文件的更新时光会更新,而 rwd 不会将文件的元数据刷盘

两个 SocketChannel 

因为这俩一个担当跟尾传输,另外一个担当跟尾的监听,所以就放在一起来讲了。这一小节我们可能要做这件事:

客户端发送文件到服务器

然则为了能让巨匠间接运行起来,客户端这侧就不从磁盘文件读取了,间接用 ByteBuffer。巨匠可以或许运行起来当前,自身查验测验从磁盘上去加载。照旧先看代码,首先是服务器的:

ServerSocketChannel
public static void main(String[] args) throws IOException {   // 关上一个 ServerSocketChannel   ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();   // 绑定 8080 端口   serverSocketChannel.bind(new InetSocketAddress(8080));    // 起头担当客户端跟尾   SocketChannel socketChannel = serverSocketChannel.accept();   // 取得跟尾告成   System.out.printf("socketChannel %s connected\n", socketChannel);   // 操办 ByteBuffer 以从 socketChannel 中读取数据   ByteBuffer buffer = ByteBuffer.allocate(16);    // 起头读取数据   System.out.println("before read");   int read = socketChannel.read(buffer);   System.out.printf("read complete, read bytes length: %s \n", read);    printBuffer(buffer); } 

这里我们运用的是 Java NIO 中默认的壅闭情势,仅仅作为一个遮盖,假定想要 ServerSocketChannel 进入非壅闭情势,可在 open 当前,调用:

serverSocketChannel.configureBlocking(false); 

因为我们这里是壅闭情势,所以在代码运行到 serverSocketChannel.accept(); 时,会陷入壅闭形态,直到有客户端已往直立跟尾。同理,read 编制也是壅闭的,假定客户端一贯没有写入数据,那末服务器就会一贯壅闭在 read 。

SocketChannel

间接先给代码:

public static void main(String[] args) throws IOException {   // 关上一个 SocketChannel   SocketChannel socketChannel = SocketChannel.open();   // 跟尾到 localhost 的 8080 端口   socketChannel.connect(new InetSocketAddress("localhost", 8080));    // 操办 ByteBuffer   ByteBuffer buffer = ByteBuffer.allocate(16);   buffer.put(Charset.defaultCharset().encode("test"));    // 将 buffer 切换成读情势 & 向 channel 中写入数据   buffer.flip();   socketChannel.write(buffer); } 

先启动服务器,再启动客户端。可以或许看到服务器侧的掌握台有以下的输出:

socketChannel java.nio.channels.SocketChannel[connected local=/127.0.0.1:8080 remote=/127.0.0.1:64373] connected before read read complete, read bytes length: 4  BUFFER VALUE: test 
Datagram

这个就相比俭朴,首先是客户端的代码:

public static void main(String[] args) throws IOException {   DatagramChannel datagramChannel = DatagramChannel.open();    // 构建 buffer 数据   ByteBuffer buffer = ByteBuffer.allocate(16);   buffer.put(Charset.defaultCharset().encode("test"));    // 切换到 buffer 的读情势   buffer.flip();   datagramChannel.send(buffer, new InetSocketAddress("localhost", 8080)); } 

尔后是服务器:

public static void main(String[] args) throws IOException {   DatagramChannel datagramChannel = DatagramChannel.open();   datagramChannel.bind(new InetSocketAddress(8080));    ByteBuffer buffer = ByteBuffer.allocate(16);   datagramChannel.receive(buffer);    printBuffer(buffer); } 

 



上一篇:WSA 可抉择调用 GPU 显卡!微软 Windows 11 安卓子体系 1.8.32836 更新
下一篇:异性交往,遇见了灵魂伴侣,才会有这三种感到