成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一篇文章讀不懂:IO vs. NIO

存儲 存儲軟件
處理輸入和輸出是Java程序員的常見任務,本教程中,我們將介紹 原始的 java.io (IO) 庫和較新的 java.nio (NIO) 庫 以及它們在通過網絡進行通信時的區別。.

[[320131]]

1. 概覽

處理輸入和輸出是Java程序員的常見任務,本教程中,我們將介紹 原始的 java.io (IO) 庫和較新的 java.nio (NIO) 庫 以及它們在通過網絡進行通信時的區別。.

2. 關鍵特性

讓我們先來看看這兩個包的關鍵特性。

2.1. IO – java.io

java.io 包是在Java 1.0引入的,而Reader 則是在 Java 1.1中引入。它提供:

  • InputStream 和 OutputStream – 一次提供一個字節的數據。
  • Reader 和 Writer – 包裝流
  • 阻塞模式(blocking mode) – 等待完整的消息

2.2. NIO – java.nio

java.nio 包在Java 1.4中被引入 并在 Java 1.7 (NIO.2) 更新了,其中包含 增強的文件操作 和 ASynchronousSocketChannel。它提供 :

  • Buffer – 一個讀取數據塊
  • CharsetDecoder – 用于將原始字節映射到可讀字符/從可讀字符映射原始字節
  • Channel – 與外界溝通
  • Selector – 在 SelectableChannel 上啟用多路復用,并提供對任何準備好進行I/O的 Channels 的訪問
  • 非阻塞模式(non-blocking mode) – 讀取任何準備好的東西

現在,讓我們看看在向服務器發送數據或讀取其響應時如何使用這些包。

3. 配置測試服務器

在這里,我們將使用 WireMock 來模擬另一臺服務器,以便我們可以獨立運行測試。

配置這臺服務器來監聽請求,并像真正的web服務器一樣向我們發送響應。同時我們還將使用動態端口,這樣就不會與本地計算機上的任何服務沖突。

讓我們添加WireMock Maven依賴項到 test scope:

Let's add the Maven dependency for WireMock with test scope:

  1. <dependency> 
  2.     <groupId>com.github.tomakehurst</groupId> 
  3.     <artifactId>wiremock-jre8</artifactId> 
  4.     <version>2.26.3</version> 
  5.     <scope>test</scope> 
  6. </dependency> 

 

在測試類中,讓我們定義一個 JUnit*@Rule* 來在空閑端口上啟動 WireMock 。然后,我們將對其進行配置,使其在要求預定義資源時返回一個 HTTP 200 響應,消息體為 JSON 格式的文本:

  1. @Rule public WireMockRule wireMockRule = new WireMockRule(wireMockConfig().dynamicPort()); 
  2.   
  3. private String REQUESTED_RESOURCE = "/test.json"
  4.   
  5. @Before 
  6. public void setup() { 
  7.     stubFor(get(urlEqualTo(REQUESTED_RESOURCE)) 
  8.       .willReturn(aResponse() 
  9.       .withStatus(200) 
  10.       .withBody("{ \"response\" : \"It worked!\" }"))); 

現在已經建立了模擬服務器,我們準備運行一些測試。

4. Blocking IO – java.io

我們可通過從網站上讀取一些數據來了解原始的阻塞IO模型是如何工作的,例如:使用一個 java.net.Socket 來訪問操作系統的一個端口。

4.1. 發送請求(Request)

在這個例子中,我們將創建一個GET請求來檢索資源。首先,創建一個 Socket 來訪問我們的WireMock服務器正在監聽的端口:

  1. Socket socket = new Socket("localhost", wireMockRule.port() 

對于普通的 HTTP 或 HTTPS 通信,端口應該是 80 或 443 。但是,在本例中,我們使用wireMockRule.port() 來訪問前面設置的動態端口。現在,我們在套接字上打開一個 OutputStream ,包裝在 OutputStreamWriter 中,并將其傳遞給 PrintWiter 來編寫我們的消息。確保刷新緩沖區以便發送我們的請求:

  1. OutputStream clientOutput = socket.getOutputStream(); 
  2. PrintWriter writer = new PrintWriter(new OutputStreamWriter(clientOutput)); 
  3. writer.print("GET " + TEST_JSON + " HTTP/1.0\r\n\r\n"); 
  4. writer.flush(); 

4.2. 等待響應(Response)

打開套接字上的 InputStream 來獲取響應,使用 BufferedReader 讀取流,并將其存儲在 StringBuilder 中:

  1. InputStream serverInput = socket.getInputStream(); 
  2. BufferedReader reader = new BufferedReader(new InputStreamReader(serverInput)); 
  3. StringBuilder ourStore = new StringBuilder(); 

我們使用 reader.readLine() 來阻塞,等待一個完整的行,然后將該行追加到我們的存儲中。我們將一直讀取,直到得到一個空值,它指示流的結尾:

  1. for (String line; (line = reader.readLine()) != null;) { 
  2.    ourStore.append(line); 
  3.    ourStore.append(System.lineSeparator()); 

5. Non-Blocking IO – java.nio

現在,讓我們看看 NIO包 的非阻塞IO模型是如何與同一個例子一起工作的。

這次,我們將創建一個 java.nio.channel.SocketChannel 來訪問服務器上的端口,而不是java.net.Socket,并向它傳遞一個InetSocketAddress。

5.1. 發送 Request

首先, 打開 SocketChannel:

  1. InetSocketAddress address = new InetSocketAddress("localhost", wireMockRule.port()); 
  2. SocketChannel socketChannel = SocketChannel.open(address); 

現在,讓我們使用一個標準的UTF-8字符集 來編碼和編寫我們的消息:

  1. Charset charset = StandardCharsets.UTF_8; 
  2. socket.write(charset.encode(CharBuffer.wrap("GET " + REQUESTED_RESOURCE + " HTTP/1.0\r\n\r\n"))); 

5.2. 讀取 Response

發送請求后,我們可以使用原始緩沖區以非阻塞模式讀取響應。

既然要處理文本,那么我們需要一個 ByteBuffer 來處理原始字節,一個CharBuffer 用來轉換字符(借助 CharsetDecoder):

  1. ByteBuffer byteBuffer = ByteBuffer.allocate(8192); 
  2. CharsetDecoder charsetDecoder = charset.newDecoder(); 
  3. CharBuffer charBuffer = CharBuffer.allocate(8192); 

如果數據是以多字節字符集發送的,CharBuffer 將有剩余空間。

注意,如果需要特別快的性能,我們可以使用 ByteBuffer.allocateDirect() 在本機內存中創建一個MappedByteBuffer。然而,在我們的例子中,從標準堆中使用 allocate() 已經足夠快了。

在處理緩沖區時,我們需要知道緩沖區有多大(capacity),我們在緩沖區中的位置(current position),以及我們能走多遠(limit)。

所以,我們從SocketChannel中讀取,將它傳遞給 ByteBuffer 來存儲我們的數據。從 SocketChannel讀取將以 ByteBuffer的當前位置為下一個要寫入的字節(就在寫入最后一個字節之后)結束,但其限制(limit)不變:

  1. socketChannel.read(byteBuffer) 

Our SocketChannel.read() 返回可以寫入緩沖區的讀取字節數 ,如果斷開連接,則會變成 -1.

當緩沖區由于尚未處理其所有數據而沒有剩余空間時,SocketChannel.read() 將返回讀取的零字節,但buffer.position() 仍將大于零。

確保從緩沖區的正確位置開始讀取, 我們將使用 Buffer.flip() 來設置 ByteBuffer 的當前位置為0 以及它對 SocketChannel 寫入的最后一個字節的限制。然后,我們將使用 storeBufferContents 方法保存緩沖區內容,稍后我們將查看該方法。最后,使用 buffer.compact() 壓縮緩沖區并設置當前位置,以便下次從 SocketChannel 讀取。

由于數據可能部分到達,需要用終止條件將緩沖區讀取代碼包裝成一個循環,以檢查套接字是否仍然連接,或者是否已斷開連接,但緩沖區中仍有數據:

  1. while (socketChannel.read(byteBuffer) != -1 || byteBuffer.position() > 0) { 
  2.     byteBuffer.flip(); 
  3.     storeBufferContents(byteBuffer, charBuffer, charsetDecoder, ourStore); 
  4.     byteBuffer.compact(); 

別忘了關閉套接字(除非我們在try with resources塊中打開它):

  1. socketChannel.close(); 

5.3. Buffer存儲數據

來自服務器的響應將包含頭,這可能會使數據量超過緩沖區的大小。因此,我們將使用StringBuilder在消息到達時構建完整的消息。為了存儲我們的消息,我們首先將原始字節解碼為我們的 CharBuffer 中的字符。然后翻轉指針,以便讀取字符數據,并將其附加到可擴展的 StringBuilder. 最后,清除CharBuffer以準備下一個寫/讀循環。現在,讓我們實現傳入緩沖區的完整 storeBufferContents() 方法,CharsetDecoder 和 StringBuilder:

  1. void storeBufferContents(ByteBuffer byteBuffer, CharBuffer charBuffer,  
  2.   CharsetDecoder charsetDecoder, StringBuilder ourStore) { 
  3.     charsetDecoder.decode(byteBuffer, charBuffer, true); 
  4.     charBuffer.flip(); 
  5.     ourStore.append(charBuffer); 
  6.     charBuffer.clear(); 

6. 總結

本文中, 我們已經看到原始java.io模型如何阻塞,等待請求,并使用 Streams 來操作它接收到的數據。相反,java.nio庫允許使用Buffers和Channels進行非阻塞通信,并且可以提供直接內存訪問以獲得更快的性能。然而,這種速度帶來了處理緩沖區的額外復雜性。

在本文中,我們看到了原始 java.io 模型如何阻塞,如何等待請求并使用Streams來處理它接收到的數據。相反,java.nio庫允許使用Buffers和Channels進行非阻塞通信,并且可以提供直接內存訪問以獲得更快的性能。然而,這種速度帶來了處理緩沖區的額外復雜性。

一如既往, 代碼 over on GitHub.

 

責任編輯:武曉燕 來源: 鍋外的大佬
相關推薦

2023-05-08 08:21:15

JavaNIO編程

2020-10-09 08:15:11

JsBridge

2020-10-23 07:56:04

Java中的IO流

2017-09-05 08:52:37

Git程序員命令

2022-02-21 09:44:45

Git開源分布式

2023-05-12 08:19:12

Netty程序框架

2019-04-17 15:16:00

Sparkshuffle算法

2021-04-09 08:40:51

網絡保險網絡安全網絡風險

2021-06-30 00:20:12

Hangfire.NET平臺

2024-06-25 08:18:55

2022-02-17 08:35:59

OLTPOLAP數據倉庫

2022-02-23 09:36:11

GoRuby編程語言

2023-09-06 14:57:46

JavaScript編程語言

2020-12-08 08:09:49

SVG圖標Web

2019-09-24 14:19:12

PythonC語言文章

2021-05-18 08:30:42

JavaScript 前端JavaScript時

2021-06-24 09:05:08

JavaScript日期前端

2021-09-27 09:18:30

ListIterato接口方法

2021-01-26 23:46:32

JavaScript數據結構前端

2021-03-05 18:04:15

JavaScript循環代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: yiren22综合网成人 | 在线资源视频 | av在线免费网 | 嫩草视频免费 | 羞羞色网站| 色偷偷人人澡人人爽人人模 | 亚洲欧美日韩一区二区 | 国产视频一区在线 | 久久99精品国产 | 亚洲欧美综合精品久久成人 | 欧美日韩久久 | 中文字幕在线剧情 | 欧美性乱| 国产伦精品一区二区三毛 | 日本午夜一区二区三区 | 精品熟人一区二区三区四区 | 国产粉嫩尤物极品99综合精品 | 久久午夜国产精品www忘忧草 | 一级毛片中国 | 在线不卡视频 | 日韩欧美在线观看视频网站 | 96国产精品久久久久aⅴ四区 | 亚洲性视频在线 | 九九九色 | 伊人青青久久 | 91精品国产乱码久久久久久久久 | 成年人黄色免费视频 | 一起操网站 | 精品久久一区二区 | 亚洲一区在线日韩在线深爱 | 色伊人久久 | 91中文字幕在线 | 国产丝袜一区二区三区免费视频 | 亚洲国产一区二区三区在线观看 | 国产免费一区二区三区最新6 | 亚洲一区二区在线电影 | 最新国产精品 | 国产日韩精品在线 | 日韩视频免费在线 | 亚洲精精品| 婷婷色网 |