1. 程式人生 > >Code-lover's Learning Notes

Code-lover's Learning Notes

JDK 1.4 中引入的新輸入輸出 (NIO) 庫在標準 Java 程式碼中提供了高速的、面向塊的 I/O。本實用教程從高階概念到底層的程式設計細節,非常詳細地介紹了 NIO 庫。您將學到諸如緩衝區和通道這樣的關鍵 I/O 元素的知識,並考察更新後的庫中的標準 I/O 是如何工作的。您還將瞭解只能通過 NIO 來完成的工作,如非同步 I/O 和直接緩衝區。

在開始之前

關於本教程

新的輸入/輸出 (NIO) 庫是在 JDK 1.4 中引入的。NIO 彌補了原來的 I/O 的不足,它在標準 Java 程式碼中提供了高速的、面向塊的 I/O。通過定義包含資料的類,以及通過以塊的形式處理這些資料,NIO 不用使用本機程式碼就可以利用低階優化,這是原來的 I/O 包所無法做到的。

在本教程中,我們將討論 NIO 庫的幾乎所有方面,從高階的概念性內容到底層的程式設計細節。除了學習諸如緩衝區和通道這樣的關鍵 I/O 元素外,您還有機會看到在更新後的庫中標準 I/O 是如何工作的。您還會了解只能通過 NIO 來完成的工作,如非同步 I/O 和直接緩衝區。

在本教程中,我們將使用展示 NIO 庫的不同方面的程式碼示例。幾乎每一個程式碼示例都是一個大的 Java 程式的一部分,您可以在 參考資料 中找到這個 Java 程式。在做這些練習時,我們推薦您在自己的系統上下載、編譯和執行這些程式。在您學習了本教程以後,這些程式碼將為您的 NIO 程式設計努力提供一個起點。

本教程是為希望學習更多關於 JDK 1.4 NIO 庫的知識的所有程式設計師而寫的。為了最大程度地從這裡的討論中獲益,您應該理解基本的 Java 程式設計概念,如類、繼承和使用包。多少熟悉一些原來的 I/O 庫(來自 java.io.*

 包)也會有所幫助。

雖然本教程要求掌握 Java 語言的工作詞彙和概念,但是不需要有很多實際程式設計經驗。除了徹底介紹與本教程有關的所有概念外,我還保持程式碼示例儘可能短小和簡單。目的是讓即使沒有多少 Java 程式設計經驗的讀者也能容易地開始學習 NIO。

如何執行程式碼

原始碼歸檔檔案(在 參考資料 中提供)包含了本教程中使用的所有程式。每一個程式都由一個 Java 檔案構成。每一個檔案都根據名稱來識別,並且可以容易地與它所展示的程式設計概念相關聯。

教程中的一些程式需要命令列引數才能執行。要從命令列執行一個程式,只需使用最方便的命令列提示符。在 Windows 中,命令列提供符是 “Command” 或者 “command.com” 程式。在 UNIX 中,可以使用任何 shell。

需要安裝 JDK 1.4 並將它包括在路徑中,才能完成本教程中的練習。如果需要安裝和配置 JDK 1.4 的幫助,請參見 參考資料 。

輸入/輸出:概念性描述

I/O 簡介

I/O ? 或者輸入/輸出 ? 指的是計算機與外部世界或者一個程式與計算機的其餘部分的之間的介面。它對於任何計算機系統都非常關鍵,因而所有 I/O 的主體實際上是內建在作業系統中的。單獨的程式一般是讓系統為它們完成大部分的工作。

在 Java 程式設計中,直到最近一直使用 流 的方式完成 I/O。所有 I/O 都被視為單個的位元組的移動,通過一個稱為 Stream 的物件一次移動一個位元組。流 I/O 用於與外部世界接觸。它也在內部使用,用於將物件轉換為位元組,然後再轉換回物件。

NIO 與原來的 I/O 有同樣的作用和目的,但是它使用不同的方式? 塊 I/O。正如您將在本教程中學到的,塊 I/O 的效率可以比流 I/O 高許多。

為什麼要使用 NIO?

NIO 的建立目的是為了讓 Java 程式設計師可以實現高速 I/O 而無需編寫自定義的本機程式碼。NIO 將最耗時的 I/O 操作(即填充和提取緩衝區)轉移回作業系統,因而可以極大地提高速度。

流與塊的比較

原來的 I/O 庫(在 java.io.*中) 與 NIO 最重要的區別是資料打包和傳輸的方式。正如前面提到的,原來的 I/O 以流的方式處理資料,而 NIO 以塊的方式處理資料。

面向流 的 I/O 系統一次一個位元組地處理資料。一個輸入流產生一個位元組的資料,一個輸出流消費一個位元組的資料。為流式資料建立過濾器非常容易。連結幾個過濾器,以便每個過濾器只負責單個複雜處理機制的一部分,這樣也是相對簡單的。不利的一面是,面向流的 I/O 通常相當慢。

一個 面向塊 的 I/O 系統以塊的形式處理資料。每一個操作都在一步中產生或者消費一個數據塊。按塊處理資料比按(流式的)位元組處理資料要快得多。但是面向塊的 I/O 缺少一些面向流的 I/O 所具有的優雅性和簡單性。

整合的 I/O

在 JDK 1.4 中原來的 I/O 包和 NIO 已經很好地集成了。 java.io.* 已經以 NIO 為基礎重新實現了,所以現在它可以利用 NIO 的一些特性。例如, java.io.* 包中的一些類包含以塊的形式讀寫資料的方法,這使得即使在更面向流的系統中,處理速度也會更快。

也可以用 NIO 庫實現標準 I/O 功能。例如,可以容易地使用塊 I/O 一次一個位元組地移動資料。但是正如您會看到的,NIO 還提供了原 I/O 包中所沒有的許多好處。

通道和緩衝區

概述

通道 和 緩衝區 是 NIO 中的核心物件,幾乎在每一個 I/O 操作中都要使用它們。

通道是對原 I/O 包中的流的模擬。到任何目的地(或來自任何地方)的所有資料都必須通過一個 Channel 物件。一個 Buffer 實質上是一個容器物件。傳送給一個通道的所有物件都必須首先放到緩衝區中;同樣地,從通道中讀取的任何資料都要讀到緩衝區中。

在本節中,您會了解到 NIO 中通道和緩衝區是如何工作的。

什麼是緩衝區?

Buffer 是一個物件, 它包含一些要寫入或者剛讀出的資料。 在 NIO 中加入 Buffer 物件,體現了新庫與原 I/O 的一個重要區別。在面向流的 I/O 中,您將資料直接寫入或者將資料直接讀到 Stream 物件中。

在 NIO 庫中,所有資料都是用緩衝區處理的。在讀取資料時,它是直接讀到緩衝區中的。在寫入資料時,它是寫入到緩衝區中的。任何時候訪問 NIO 中的資料,您都是將它放到緩衝區中。

緩衝區實質上是一個數組。通常它是一個位元組陣列,但是也可以使用其他種類的陣列。但是一個緩衝區不 僅僅 是一個數組。緩衝區提供了對資料的結構化訪問,而且還可以跟蹤系統的讀/寫程序。

緩衝區型別

最常用的緩衝區型別是 ByteBuffer。一個 ByteBuffer 可以在其底層位元組陣列上進行 get/set 操作(即位元組的獲取和設定)。

ByteBuffer 不是 NIO 中唯一的緩衝區型別。事實上,對於每一種基本 Java 型別都有一種緩衝區型別:

  • ByteBuffer
  • CharBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FloatBuffer
  • DoubleBuffer

每一個 Buffer 類都是 Buffer 介面的一個例項。 除了 ByteBuffer,每一個 Buffer 類都有完全一樣的操作,只是它們所處理的資料型別不一樣。因為大多數標準 I/O 操作都使用 ByteBuffer,所以它具有所有共享的緩衝區操作以及一些特有的操作。

現在您可以花一點時間執行 UseFloatBuffer.java,它包含了型別化的緩衝區的一個應用例子。

什麼是通道?

Channel是一個物件,可以通過它讀取和寫入資料。拿 NIO 與原來的 I/O 做個比較,通道就像是流。

正如前面提到的,所有資料都通過 Buffer 物件來處理。您永遠不會將位元組直接寫入通道中,相反,您是將資料寫入包含一個或者多個位元組的緩衝區。同樣,您不會直接從通道中讀取位元組,而是將資料從通道讀入緩衝區,再從緩衝區獲取這個位元組。

通道型別

通道與流的不同之處在於通道是雙向的。而流只是在一個方向上移動(一個流必須是 InputStream 或者 OutputStream 的子類), 而 通道 可以用於讀、寫或者同時用於讀寫。

因為它們是雙向的,所以通道可以比流更好地反映底層作業系統的真實情況。特別是在 UNIX 模型中,底層作業系統通道是雙向的。

從理論到實踐:NIO 中的讀和寫

概述

讀和寫是 I/O 的基本過程。從一個通道中讀取很簡單:只需建立一個緩衝區,然後讓通道將資料讀到這個緩衝區中。寫入也相當簡單:建立一個緩衝區,用資料填充它,然後讓通道用這些資料來執行寫入操作。

在本節中,我們將學習有關在 Java 程式中讀取和寫入資料的一些知識。我們將回顧 NIO 的主要元件(緩衝區、通道和一些相關的方法),看看它們是如何互動以進行讀寫的。在接下來的幾節中,我們將更詳細地分析這其中的每個元件以及其互動。

從檔案中讀取

在我們第一個練習中,我們將從一個檔案中讀取一些資料。如果使用原來的 I/O,那麼我們只需建立一個 FileInputStream 並從它那裡讀取。而在 NIO 中,情況稍有不同:我們首先從 FileInputStream 獲取一個 Channel 物件,然後使用這個通道來讀取資料。

在 NIO 系統中,任何時候執行一個讀操作,您都是從通道中讀取,但是您不是 直接 從通道讀取。因為所有資料最終都駐留在緩衝區中,所以您是從通道讀到緩衝區中。

因此讀取檔案涉及三個步驟:(1) 從 FileInputStream 獲取 Channel,(2) 建立 Buffer,(3) 將資料從 Channel 讀到 Buffer 中。

現在,讓我們看一下這個過程。

三個容易的步驟

第一步是獲取通道。我們從 FileInputStream 獲取通道:

FileInputStream fin = new FileInputStream( "readandshow.txt" );
FileChannel fc = fin.getChannel();

下一步是建立緩衝區:

ByteBuffer buffer = ByteBuffer.allocate( 1024 );

最後,需要將資料從通道讀到緩衝區中,如下所示:

fc.read( buffer );

您會注意到,我們不需要告訴通道要讀 多少資料 到緩衝區中。每一個緩衝區都有複雜的內部統計機制,它會跟蹤已經讀了多少資料以及還有多少空間可以容納更多的資料。我們將在 緩衝區內部細節 中介紹更多關於緩衝區統計機制的內容。

寫入檔案

在 NIO 中寫入檔案類似於從檔案中讀取。首先從 FileOutputStream 獲取一個通道:

FileOutputStream fout = new FileOutputStream( "writesomebytes.txt" );
FileChannel fc = fout.getChannel();

下一步是建立一個緩衝區並在其中放入一些資料 - 在這裡,資料將從一個名為 message 的陣列中取出,這個陣列包含字串 "Some bytes" 的 ASCII 位元組(本教程後面將會解釋 buffer.flip() 和 buffer.put() 呼叫)。

ByteBuffer buffer = ByteBuffer.allocate( 1024 );

for (int i=0; i<message.length; ++i) {
     buffer.put( message[i] );
}
buffer.flip();

最後一步是寫入緩衝區中:

fc.write( buffer );

注意在這裡同樣不需要告訴通道要寫入多資料。緩衝區的內部統計機制會跟蹤它包含多少資料以及還有多少資料要寫入。

讀寫結合

下面我們將看一下在結合讀和寫時會有什麼情況。我們以一個名為 CopyFile.java 的簡單程式作為這個練習的基礎,它將一個檔案的所有內容拷貝到另一個檔案中。CopyFile.java 執行三個基本操作:首先建立一個 Buffer,然後從原始檔中將資料讀到這個緩衝區中,然後將緩衝區寫入目標檔案。這個程式不斷重複 ― 讀、寫、讀、寫 ― 直到原始檔結束。

CopyFile 程式讓您看到我們如何檢查操作的狀態,以及如何使用 clear() 和 flip() 方法重設緩衝區,並準備緩衝區以便將新讀取的資料寫到另一個通道中。

執行 CopyFile 例子

因為緩衝區會跟蹤它自己的資料,所以 CopyFile 程式的內部迴圈 (inner loop) 非常簡單,如下所示:

fcin.read( buffer );
fcout.write( buffer );

第一行將資料從輸入通道 fcin 中讀入緩衝區,第二行將這些資料寫到輸出通道 fcout 。

檢查狀態

下一步是檢查拷貝何時完成。當沒有更多的資料時,拷貝就算完成,並且可以在 read() 方法返回 -1 是判斷這一點,如下所示:

int r = fcin.read( buffer );

if (r==-1) {
     break;
}

重設緩衝區

最後,在從輸入通道讀入緩衝區之前,我們呼叫 clear() 方法。同樣,在將緩衝區寫入輸出通道之前,我們呼叫 flip() 方法,如下所示:

buffer.clear();
int r = fcin.read( buffer );

if (r==-1) {
     break;
}

buffer.flip();
fcout.write( buffer );

clear() 方法重設緩衝區,使它可以接受讀入的資料。 flip() 方法讓緩衝區可以將新讀入的資料寫入另一個通道。

緩衝區內部細節

概述

本節將介紹 NIO 中兩個重要的緩衝區元件:狀態變數和訪問方法 (accessor)。

狀態變數是前一節中提到的"內部統計機制"的關鍵。每一個讀/寫操作都會改變緩衝區的狀態。通過記錄和跟蹤這些變化,緩衝區就可能夠內部地管理自己的資源。

在從通道讀取資料時,資料被放入到緩衝區。在有些情況下,可以將這個緩衝區直接寫入另一個通道,但是在一般情況下,您還需要檢視資料。這是使用 訪問方法 get() 來完成的。同樣,如果要將原始資料放入緩衝區中,就要使用訪問方法 put()

在本節中,您將學習關於 NIO 中的狀態變數和訪問方法的內容。我們將描述每一個元件,並讓您有機會看到它的實際應用。雖然 NIO 的內部統計機制初看起來可能很複雜,但是您很快就會看到大部分的實際工作都已經替您完成了。您可能習慣於通過手工編碼進行簿記 ― 即使用位元組陣列和索引變數,現在它已在 NIO 中內部地處理了。

狀態變數

可以用三個值指定緩衝區在任意時刻的狀態:

  • position
  • limit
  • capacity

這三個變數一起可以跟蹤緩衝區的狀態和它所包含的資料。我們將在下面的小節中詳細分析每一個變數,還要介紹它們如何適應典型的讀/寫(輸入/輸出)程序。在這個例子中,我們假定要將資料從一個輸入通道拷貝到一個輸出通道。

Position

您可以回想一下,緩衝區實際上就是美化了的陣列。在從通道讀取時,您將所讀取的資料放到底層的陣列中。 position 變數跟蹤已經寫了多少資料。更準確地說,它指定了下一個位元組將放到陣列的哪一個元素中。因此,如果您從通道中讀三個位元組到緩衝區中,那麼緩衝區的position 將會設定為3,指向陣列中第四個元素。

同樣,在寫入通道時,您是從緩衝區中獲取資料。 position 值跟蹤從緩衝區中獲取了多少資料。更準確地說,它指定下一個位元組來自陣列的哪一個元素。因此如果從緩衝區寫了5個位元組到通道中,那麼緩衝區的 position 將被設定為5,指向陣列的第六個元素。

Limit

limit 變量表明還有多少資料需要取出(在從緩衝區寫入通道時),或者還有多少空間可以放入資料(在從通道讀入緩衝區時)。

position 總是小於或者等於 limit

Capacity

緩衝區的 capacity 表明可以儲存在緩衝區中的最大資料容量。實際上,它指定了底層陣列的大小 ― 或者至少是指定了准許我們使用的底層陣列的容量。

limit 決不能大於 capacity

觀察變數

我們首先觀察一個新建立的緩衝區。出於本例子的需要,我們假設這個緩衝區的 總容量 為8個位元組。 Buffer 的狀態如下所示:


回想一下 ,limit 決不能大於 capacity,此例中這兩個值都被設定為 8。我們通過將它們指向陣列的尾部之後(如果有第8個槽,則是第8個槽所在的位置)來說明這點。


position 設定為0。如果我們讀一些資料到緩衝區中,那麼下一個讀取的資料就進入 slot 0 。如果我們從緩衝區寫一些資料,從緩衝區讀取的下一個位元組就來自 slot 0 。 position 設定如下所示:


由於 capacity 不會改變,所以我們在下面的討論中可以忽略它。

第一次讀取

現在我們可以開始在新建立的緩衝區上進行讀/寫操作。首先從輸入通道中讀一些資料到緩衝區中。第一次讀取得到三個位元組。它們被放到陣列中從 position 開始的位置,這時 position 被設定為 0。讀完之後,position 就增加到 3,如下所示:


limit 沒有改變。

第二次讀取

在第二次讀取時,我們從輸入通道讀取另外兩個位元組到緩衝區中。這兩個位元組儲存在由 position 所指定的位置上, 

相關推薦

Code-lover's Learning Notes

JDK 1.4 中引入的新輸入輸出 (NIO) 庫在標準 Java 程式碼中提供了高速的、面向塊的 I/O。本實用教程從高階概念到底層的程式設計細節,非常詳細地介紹了 NIO 庫。您將學到諸如緩衝區和通道這樣的關鍵 I/O 元素的知識,並考察更新後的庫中的標準 I/O

Cethy‘s Learning Notes

KITTI資料集感謝~收藏用!摘要:本文融合了Are we ready for Autonomous Driving? The KITTI Vision Benchmark Suite和Vision meets Robotics: The KITTI Dataset兩篇論文的

34 day's learning is ooooooover!

    The 34 day's learning is over, and I can't control myself to write this, 'cause those fuck days I lived with a devil !    

ErosJohn's Learning House

0x01 上次爬取ichunqiu網課發現它是post請求,為了爬取後續課程名,修改了一下程式碼。 0x02 程式碼如下: (歡迎探討) import requests import json url = 'https://www.ichunqiu.com/co

《Tensorflow | 莫煩 》learning notes

強烈建議先看 5.7 節,哈哈! 1 Tensorflow 簡介 1.1 科普: 人工神經網路 VS 生物神經網路 兩者的區別 人工神經網路靠的是正向和反向傳播來更新神經元, 從而形成一個好的神經系統, 本質上, 這是一個能讓計算機處理和優化的數學模

Kuroko's Development Notes

Charles:青花瓷抓包工具。 破解版安裝方式: 通過上方破解版下載連結下載解壓之後。 1、直接開啟 charles-proxy-4.2.5.dmg 安裝青花瓷。 2、複製 char

A beginner’s python notes

PRIMARY KEYprimary key用來保證欄位在資料表中的唯一性,主鍵欄位中的每一筆資料在資料表中都必需是獨一無二的。primary key 是該table 中具有唯一性與識別性的資料,若沒有單一資料具有此特性,也可以是兩個以上的資料合成具有此特性的key 值,即可做為primary key。一個資

Meet The Dog That’s Learning How to Help Save An Endangered Owl

An owl pellet, also known by falconers as a casting, is similar to a hairball coughed up by a cat, except an owl pellet contains the undigestible remains o

Python learning notes — Those cool stuff

L-layer Neural NetworkShape of the vectorsIf the size of our input XX is (12288,209) (with m=209 examples) then:

Learning Notes】變分自編碼器(Variational Auto-Encoder,VAE)

近年,隨著有監督學習的低枝果實被採摘的所剩無幾,無監督學習成為了研究熱點。VAE(Variational Auto-Encoder,變分自編碼器)[1,2] 和 GAN(Generative Adversarial Networks) 等模型,受到越來越多的關注

my learning notes

onclick="javascript:window.history.back(-1);" 方法一、以按鈕點選的方式實現: <input type="button" name="Submit

Learning Notes】生成式對抗網路(Generative Adversarial Networks,GAN)

在學習 Variational Auto-Encoder時,同時注意到了 GAN 研究的火熱。但當時覺得 GAN 非常不成熟(訓練不穩定,依賴各種說不清的 tricks;沒有有效的監控指標,需要大量的人工判斷,因此難以擴展到圖像之外的高維數據)。在讀了 Good

learning notes

引言 最近做人臉識別相關,需要用到微軟的 MS-celeb-1M資料集,接觸到了md5格式檔案 求助百度百科md5成功,求助wikipediamd5成功。 md5 是一種使用hash 函式來產生128-bit的hash值。 特點 MD5演算法具有以

Objective-C Learning notes

There Some points in Objective-C just like NSString,NSArray,NSDictionary,Protocol,interface,abort dealing,Delegate,Listeners and mo

Deep Learning Notes: Chapter 1 Introduction

前言 最近開始讀《Deep Learning》一書。這讓我有了一個邊讀書邊寫筆記的動機:能夠讓人很輕鬆流暢的把握住這本書的脈絡,從而讀懂這本書的核心內容。 由於終究是英文表達更地道,因此該筆記都是節選自書中的原文。只有在我比較有把握的情況下才會給個別概念加上

Learning Notes】CTC 原理及實現

CTC( Connectionist Temporal Classification,連線時序分類)是一種用於序列建模的工具,其核心是定義了特殊的目標函式/優化準則[1]。 jupyter notebook 版見 repo. 1. 演算法 這裡

Android Service learning notes

Service As one of the four major components of Android, it is used to perform a number of tasks that do not require user interaction as

Pagedown learning notes

有效 edi nload cdn 白名單 converter var div name Pagedown Links Google wiki page Download Markdown.Converter.js var converter = new Markdown

[CodeForces - 614B] B - Gena's Code

std specified note doesn fin imp order codeforce sed A - Link/Cut Tree Programmer Rostislav got seriously interested in the Link/Cut Tree

CS 229 notes Supervised Learning

pmf ocm borde pem clu hex nts blog wid CS 229 notes Supervised Learning 標簽(空格分隔): 監督學習 線性代數 Forword the proof of Normal equation and, b