激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 一篇學會 Java NIO Channel 的使用

一篇學會 Java NIO Channel 的使用

2022-01-12 23:45SH的全棧筆記 Java教程

本篇文章主要對Java NIO Channel 的使用簡要說明,具有一定的參考價值,下面跟著小編一起來看下吧..

一篇學會 Java NIO Channel 的使用

Java NIO 中的 Channel 分類:

  • FileChannel
  • SocketChannel
  • ServerSocketChannel
  • DatagramChannel

一篇學會 Java NIO Channel 的使用

channel 分類

FileChannel: 主要用于文件的讀寫,可以從磁盤上讀取文件,也可以向磁盤上寫入文件。

SocketChannel:用于 Socket 的 TCP 連接的數據讀寫,既可以從 Channel 讀數據,也可以向 Channle 中寫入數據

ServerSocketChannel:通過 ServerSocketChannel 可以監聽 TCP 連接,服務端監聽到連接之后,會為每個請求創建一個 SocketChannel

DatagramChannel:用于 UDP 協議的數據讀寫

接下來就分別介紹一下。

FileChannel

主要用于操作文件,廢話不多說,直接看例子。

準備文件 test-file.txt ,內容 shDEQuanZhanBiJi

一篇學會 Java NIO Channel 的使用

test-file.txt 文件

輸入 FileInputStream

用于從 FileChannel 中讀取數據,例如將指定文件輸入到 FileChannel 中,我們就能獲取到文件的內容,接下來編寫 FileChannel 的 輸入流 核心代碼:

  1. public static void main(String[] args) throws IOException { 
  2.   // 創建一個輸入流 
  3.   FileInputStream fileInputStream = new FileInputStream("test-file.txt"); 
  4.   // 通過輸入流獲取到 channel 
  5.   FileChannel fileChannel = fileInputStream.getChannel(); 
  6.  
  7.   // 準備好 ByteBuffer 
  8.   ByteBuffer buffer = ByteBuffer.allocate(16); 
  9.   // 將 輸入流 的 channel 的數據讀入 buffer 中 
  10.   fileChannel.read(buffer); 
  11.  
  12.   // 簡單打印 buffer 的內容 
  13.   printBuffer(buffer); // shDEQuanZhanBiJi 

這里面的 ByteBuffer 是 channel 進行讀、寫數據的中間媒介。要從 channel 中讀取數據(也就是上面這個例子),需要先將數據讀到 ByteBuffer 中;同理,要想向 channel 中寫入數據,也需要先將數據寫入 ByteBuffer(下面講輸出流的時候會講)。

對 ByteBuffer 不熟悉的可以先看看我之前寫的《玩轉 ByteBuffer》,printBuffer 的代碼里面也有

輸出 FileOutputStream

顧名思義,是 FileChannel 要向外輸出數據,例如將數據寫入到磁盤文件上,接下來通過例子看看效果:

  1. public static void main(String[] args) throws IOException { 
  2.   // 指定需要生成的文件名稱 
  3.   String generateFileName = "generate-file.txt"
  4.   // 創建一個輸出流 
  5.   FileOutputStream fileOutputStream = new FileOutputStream(generateFileName); 
  6.   // 通過輸出流獲取到 channel 
  7.   FileChannel fileChannel = fileOutputStream.getChannel(); 
  8.  
  9.   // 準備好 ByteBuffer, 并向里面寫入數據 
  10.   ByteBuffer buffer = ByteBuffer.allocate(16); 
  11.   buffer.put("shDEQuanZhanBiJi".getBytes(StandardCharsets.UTF_8)); 
  12.  
  13.   // 將 輸入流 的 channel 的數據讀入 buffer 中 
  14.   fileChannel.write(buffer); 
  15.   fileChannel.close(); 

相應的注釋都已經貼在對應的代碼上了,細節在此不再贅述。唯一需要關注的是,調用 write 寫文件到磁盤上時,也是先傳入的 ByteBuffer。

好了,當你運行完代碼你會發現,雖然文件是生成的了,但是里面卻是空白的...這其實就涉及到對 ByteBuffer 的熟悉程度了,算是埋的一個坑。

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

這是因為我們創建一個 ByteBuffer 的時候默認是處于寫模式的,此時如果去通過 position 和 limit 去讀取數據是讀不到的。所以在調用 write 之前,我們需要先將 ByteBuffer 切換到讀模式,完整代碼如下:

  1. public static void main(String[] args) throws IOException { 
  2.   // 指定需要生成的文件名稱 
  3.   String generateFileName = "generate-file.txt"
  4.   // 創建一個輸出流 
  5.   FileOutputStream fileOutputStream = new FileOutputStream(generateFileName); 
  6.   // 通過輸出流獲取到 channel 
  7.   FileChannel fileChannel = fileOutputStream.getChannel(); 
  8.  
  9.   // 準備好 ByteBuffer, 并向里面寫入數據 
  10.   ByteBuffer buffer = ByteBuffer.allocate(16); 
  11.   buffer.put("shDEQuanZhanBiJi".getBytes(StandardCharsets.UTF_8)); 
  12.  
  13.   // 將 ByteBuffer 切換到讀模式 
  14.   buffer.flip(); 
  15.   // 將 輸入流 的 channel 的數據讀入 buffer 中 
  16.   fileChannel.write(buffer); 
  17.    
  18.   fileChannel.close(); 

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

一篇學會 Java NIO Channel 的使用

但是呢,上面將的兩種要么只能寫,要么只能讀。例如 FileInputStream 如果你硬要往 channel 里懟數據,程序最后會拋出 NonWritableChannelException 異常,告訴你這玩意兒寫不了。

那有沒有一個既能寫,又能讀還能唱跳的實現呢?當然有,那就是 RandomAccessFile。

這里提一嘴,調用完 write 并不是立即就寫入磁盤,也可以在操作系統的緩存里。如果需要立即刷盤,則調用 channel.force(true); 即可。

RandomAccessFile

怎么用的呢?其實跟之前兩個差不多:

  1. public static void main(String[] args) throws IOException { 
  2.   // 指定需要生成的文件名稱 
  3.   String targetFileName = "target-file.txt"
  4.   // 創建 RandomAccessFile, 賦予可讀(r)、可寫(w)的權限 
  5.   RandomAccessFile accessFile = new RandomAccessFile(targetFileName, "rw"); 
  6.   FileChannel fileChannel = accessFile.getChannel(); 
  7.  
  8.   // 創建 ByteBuffer 并寫入數據 
  9.   ByteBuffer buffer = ByteBuffer.allocate(16); 
  10.   buffer.put("shDEQuanZhanBiJi".getBytes(StandardCharsets.UTF_8)); 
  11.   // 切換到 buffer 的讀模式 
  12.   buffer.flip(); 
  13.   // 調用 write 將 buffer 的數據寫入到 channel, channel 再寫數據到磁盤文件 
  14.   fileChannel.write(buffer); 
  15.  
  16.   // 相當于清空 buffer 
  17.   buffer.clear(); 
  18.   // 將之前寫入到 channel 的數據再讀入到 buffer 
  19.   fileChannel.read(buffer); 
  20.  
  21.   // 打印 buffer 中的內容 
  22.   printBuffer(buffer); 
  23.  
  24.   fileChannel.close(); 

運行之后的效果就是,會生成一個名為 target-file.txt 的文件,內容就是 shDEQuanZhanBiJi。并且控制臺會將之前寫入 channel 的 shDEQuanZhanBiJi 打印出來。

老規矩,細節都在注釋中。值得注意的是 new RandomAccessFile(targetFileName, "rw"); 里的 rw 。注釋里也寫了,代表賦予可讀、可寫的權限。

再值得注意的是,你不能說把 rw 改成 w。

不能這么玩,因為它就是一個單純的字符串匹配,可供選擇的就這么些:

一篇學會 Java NIO Channel 的使用

mode 類型

  • 可以看到,r 必不可少...:
  • r 只能讀
  • rw 既能讀,也能寫

rws 和 rwd 功能和 rw 大致是相同的,可讀、可寫。唯一區別是他們會將每次改動強制刷到磁盤,并且 rws 會將操作系統對該文件的元數據也一起刷盤,體現就是文件的更新時間會更新,而 rwd 不會將文件的元數據刷盤

  1. 兩個 SocketChannel 

由于這倆一個負責連接傳輸,另一個負責連接的監聽,所以就放在一起來講了。這一小節我們大概要做這件事:

一篇學會 Java NIO Channel 的使用

客戶端發送文件到服務器

但是為了能讓大家直接運行起來,客戶端這側就不從磁盤文件讀取了,直接用 ByteBuffer。大家可以運行起來之后,自己嘗試從磁盤上去加載。還是先看代碼,首先是服務器的:

ServerSocketChannel

  1. public static void main(String[] args) throws IOException { 
  2.   // 打開一個 ServerSocketChannel 
  3.   ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); 
  4.   // 綁定 8080 端口 
  5.   serverSocketChannel.bind(new InetSocketAddress(8080)); 
  6.  
  7.   // 開始接受客戶端連接 
  8.   SocketChannel socketChannel = serverSocketChannel.accept(); 
  9.   // 獲取連接成功 
  10.   System.out.printf("socketChannel %s connected\n", socketChannel); 
  11.   // 準備 ByteBuffer 以從 socketChannel 中讀取數據 
  12.   ByteBuffer buffer = ByteBuffer.allocate(16); 
  13.  
  14.   // 開始讀取數據 
  15.   System.out.println("before read"); 
  16.   int read = socketChannel.read(buffer); 
  17.   System.out.printf("read complete, read bytes length: %s \n"read); 
  18.  
  19.   printBuffer(buffer); 

這里我們使用的是 Java NIO 中默認的阻塞模式,僅僅作為一個掩飾,如果想要 ServerSocketChannel 進入非阻塞模式,可在 open 之后,調用:

  1. serverSocketChannel.configureBlocking(false); 

由于我們這里是阻塞模式,所以在代碼運行到 serverSocketChannel.accept(); 時,會陷入阻塞狀態,直到有客戶端過來建立連接。同理,read 方法也是阻塞的,如果客戶端一直沒有寫入數據,那么服務器就會一直阻塞在 read 。

SocketChannel

直接先給代碼:

  1. public static void main(String[] args) throws IOException { 
  2.   // 打開一個 SocketChannel 
  3.   SocketChannel socketChannel = SocketChannel.open(); 
  4.   // 連接到 localhost 的 8080 端口 
  5.   socketChannel.connect(new InetSocketAddress("localhost", 8080)); 
  6.  
  7.   // 準備 ByteBuffer 
  8.   ByteBuffer buffer = ByteBuffer.allocate(16); 
  9.   buffer.put(Charset.defaultCharset().encode("test")); 
  10.  
  11.   // 將 buffer 切換成讀模式 & 向 channel 中寫入數據 
  12.   buffer.flip(); 
  13.   socketChannel.write(buffer); 

先啟動服務器,再啟動客戶端。可以看到服務器側的控制臺有如下的輸出:

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

Datagram

這個就比較簡單,首先是客戶端的代碼:

  1. public static void main(String[] args) throws IOException { 
  2.   DatagramChannel datagramChannel = DatagramChannel.open(); 
  3.  
  4.   // 構建 buffer 數據 
  5.   ByteBuffer buffer = ByteBuffer.allocate(16); 
  6.   buffer.put(Charset.defaultCharset().encode("test")); 
  7.  
  8.   // 切換到 buffer 的讀模式 
  9.   buffer.flip(); 
  10.   datagramChannel.send(buffer, new InetSocketAddress("localhost", 8080)); 

然后是服務器:

  1. public static void main(String[] args) throws IOException { 
  2.   DatagramChannel datagramChannel = DatagramChannel.open(); 
  3.   datagramChannel.bind(new InetSocketAddress(8080)); 
  4.  
  5.   ByteBuffer buffer = ByteBuffer.allocate(16); 
  6.   datagramChannel.receive(buffer); 
  7.  
  8.   printBuffer(buffer); 

原文鏈接:https://mp.weixin.qq.com/s/ythx3hMMHBxpD1BiJr_zXA

延伸 · 閱讀

精彩推薦
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
主站蜘蛛池模板: 美女黄页网站免费进入 | 欧美国产第一页 | 97超级碰碰人国产在线观看 | 精品在线观看一区二区 | 美女扒开腿让男生桶爽网站 | 亚洲小视频在线 | 成人免费网站在线观看视频 | 国产成人精品区 | 亚洲一区第一页 | chinese xvideos gay| 久久久久一本一区二区青青蜜月 | 久久黄色影院 | 免费永久看羞羞片网站入口 | 91免费高清视频 | 黄视频在线网站 | 国产精品免费一区二区三区都可以 | 精国产品一区二区三区 | 欧美一级淫片免费视频黄 | 国产91免费看 | 免费黄色在线观看网站 | 国产一区二区三区视频在线 | 久久久www视频 | 欧美va亚洲 | 欧美a∨亚洲欧美亚洲 | 91社影院在线观看 | 欧美成人做爰高潮片免费视频 | 国产成人高清成人av片在线看 | 狠狠操天天射 | 久久不雅视频 | 国产精品亚洲欧美一级在线 | 欧美aaaaaaaa| 亚洲字幕av| 青青操精品 | 91综合在线观看 | 羞羞网站| 欧美日韩夜夜 | 亚洲第一页在线观看 | 免费观看一级黄色片 | 91热久久免费频精品黑人99 | 特一级黄色毛片 | 免费a级毛片大学生免费观看 |