在1990年以前,有一幫工程師們認為未來(1990年以後)會有很多小型裝置需要得到電腦操控(不得不說,想法非常超前),鑑於當時市面上並沒有任何一款程式語言能夠跨平臺,而且能夠在諸如烤麵包機這種小型裝置上運轉,所以他們決定自己創造一個,玩一把大的。
於是Java誕生了。
為了兼顧裝置之間的檔案處理,Java在誕生之初就具備了檔案讀寫能力,只不過那時候還是借用的Linux中的I/O概念。因此可以說Java的I/O體系基本上就是Linux核心I/O模型的翻版。
對於Linux而言,整個內部結構可分為三部分:底層硬體架構、核心空間和使用者空間。
核心空間中存放核心程式碼和資料,而使用者空間中存放的是不同使用者應用程序的程式碼和資料。
不管是核心空間還是使用者空間,它們都處於虛擬儲存空間(定址空間)中——現在很多計算機都是64位元作業系統的,那麼理論上,它的定址空間就是2的64次方(264):
具體Linux怎麼工作的就不說了,總之很牛逼。
從Java I/O出現以來,已經經歷了五種模型(知道就好了,不用記,也記不住,記住了也用不著):
1、阻塞I/O(Blocking I/O)
2、非阻塞I/O(Non-Blocking I/O,又叫NIO)
3、I/O複用
4、訊號驅動I/O(Signal Driven I/O)
5、非同步I/O(Asynchrnous I/O,又叫AIO)
這五種I/O模型的分類是:
看看這些圖就可以了,也不需要深究,重點還是要了解Java程式碼怎麼寫。
早期的Java I/O都是基於阻塞I/O模型的,也就是BIO,它分為兩個部分:流式部分和非流式部分。Java對流的定義是:流是一組有順序的,有起點和終點的位元組集合,是對資料傳輸的抽象——資料在裝置間的傳輸稱為流(後面的流式程式設計還會提到它)。
流式部分:是根據不同的資料流向,分為輸入流Input和輸出流Output,對輸入流只能進行讀操作,對輸出流只能進行寫操作。根據不同的資料編碼,又分為位元組流Byte和字元流Char,字元流的本質其實就是基於位元組流讀取時,通過指定的編碼表將位元組轉換為字元,位元組流可以處理所有的資料型別,而字元流只能處理字元型別的資料。
非流式部分:包含一些輔助類,如File、FileDescriptor、RandomAccessFile、SerializablePermission等,也就是直接操作具體的檔案。
按資料格式,流可以分為:
位元組流:以8位元(即1byte,8bit)作為一個資料單元,資料流中最小的資料單元是位元組。
字元流:以16位元(即1char,2byte,16bit)作為一個資料單元,資料流中最小的資料單元是字元,Java中的字元是Unicode編碼,一個字元佔用兩個位元組。
依據位元組流,Java定義了抽象基礎類別InputStream/OutputStream。
而依據字元流,Java定義了抽象基礎類別Reader/Writer。
然後Java再根據不同應用場景或功能,通過繼承這兩種抽象基礎類別派生出子類,用來滿足檔案、網路、管道等不同場景的I/O需求,從而形成了Java的基本I/O體系。
按用途,流又可以分為處理流與裝飾流:
按操作方式分類:
按操作物件分類:
一般用虛線連線的類會搭配使用:
在高效能的I/O應用中,有幾個名詞經常出現:同步/非同步、阻塞/非阻塞、同步阻塞/同步非阻塞、非同步阻塞/非同步非阻塞。
同步/非同步、阻塞/非阻塞,這兩組概念其實說的是一個事情。
同步:使用者程序觸發I/O操作並等待或者輪詢的去檢視I/O操作是否就緒,比如上廁所這件事,就必須自己親自幹,不能一邊上廁所一邊逛街;
非同步:使用者程序觸發IO操作以後就可以響應其他的任務請求,而當I/O操作完成時會得到系統通知(非同步的特點就是通知),比如把衣服丟到洗衣機裡你就會去幹別的事情了,衣服洗好了洗衣機會通知你取出來;
阻塞:和同步一樣,在程式完成指定的任務之前,什麼都不幹,一直等待著,直到完成任務,比如上廁所沒坑了,但附近又沒有別的衛生間,只好在門口一直等著;
非阻塞:和非同步一樣,不會為了某個任務或事件一直等待而不響應其他請求,比如你可以一邊上廁所一邊玩手機。
至於同步阻塞/同步非阻塞/非同步阻塞/非同步非阻塞,無非就是以上概念的變體而已。
I/O是Java中比較裹人的概念之二,非常枯燥,沒辦法。看看就行,理解不了那就多敲程式碼。