爲什麼我覺得 Java 的 IO 很複雜?

爲什麼我覺得 Java 的 IO 很複雜?

初學者覺得複雜是很正常的,歸根結底是因爲沒有理解JavaIO框架的設計思想:

可以沿着這條路想一想:

1,學IO流之前,我們寫的程序,都是在內存裏自己跟自己玩。比如,你聲明個變量,創建個數組,創建個集合,寫一個排序算法,模擬一個鏈表,使用一些常用API,現在回想一下,是不是在只是自己在內存裏玩一玩?計算機組成包括運算器,控制器,存儲器,輸入設備,輸出設備。那麼你前面的工作,僅僅夠你的程序和內存以及CPU打打交道,如果你需要操作外部設備呢?比如鍵盤,顯示器,再比如,最常見的外設:硬盤?甚至未來世界裏的每家每戶都有的機器人,“如何讓你的程序和機器人進行交互呢?”

2,所以程序設計語言必須要提供程序與外部設備交互的方式,這就是IO框架的由來。我們需要和外部設備進行數據的交互。那麼,計算機是通過什麼和外部進行交互的呢?很簡單就能想到:數據線。數據線裏傳播的是什麼呢?一個詞:比特流。比特就是bit的諧音,計算機中“位”的意思,代表0或1。1位或者1bit,就是一個0或一個1。但是,畢竟0或1不能表示什麼,所以計算機更常見的基本單位是字節,也就是用8位0或1組成的一段數據。以上是對比特流的由來做一個簡單地解釋。(比特流一詞來自於計算機網絡原理中,對物理層傳輸內容的描述:物理層(網線)中傳輸的是“比特流”,在這裏借用這個名詞代指數據的表示形式,幫助理解)上面兩段話的意思,其實是爲了下文做鋪墊,幫助理解輸入輸出最重要的概念:方向性。輸入還是輸出,是相對於程序或者說相對於內存而言的。數據從外流到內存,就是輸入(讀),數據從內存出去,就是輸出(寫)。

3,既然計算機和外界進行信息的輸入和輸出交互,用的是比特流,那麼很容易就能想到IO流名字的由來了。就是比喻輸入輸出的數據像流一樣。我們可以這麼認爲,任何外部設備與內存之間輸入輸出的操作,都是需要輸入輸出流(IO流)來完成的,這裏的IO流,指的就是比特流(或者稱字節流)。這些外部設備,包括,鍵盤(標準輸入設備),顯示器(標準輸出設備),音響,網絡上另一臺主機,甚至你玩遊戲用的遊戲手柄,以及各種各樣的信號傳感器,都可以叫做外部設備,和這些設備之間進行數據交互,顯然不可能靠之前學習的那些數組,集合,常用類,String等等來完成。而是要靠和外界數據交換的類來完成。靠什麼來進行數據交換,就是前面說的,比特流,或者說IO流類。

4,那麼,既然要學習IO流,就得針對某一個輸入輸出設備來學習。哪種輸入輸出設備最重要同時也最常見?當然是硬盤。硬盤在這裏的含義也可以理解爲文件系統。(Java程序是運行在某操作系統平臺上的應用軟件JVM上的,實際上Java程序可見的並不是硬盤,而是操作系統提供的文件系統,因此此處可直接理解爲文件系統)。因此,我們學習IO流的時候,基本上是學習的Java如何操作文件系統,除了文件系統,我們還能夠了解Java操作標準輸入輸出設備,如http://System.in和System.out。

5,知道了學習的方向,是要使用Java操作文件系統,那麼首先要學習的就是文件的表示,即File類。然後,我們要操作做文件,雖然我們大部分操作都是操作文件系統,但是要明白IO流的概念不僅僅侷限在操作文件上,前面我已經提到了,我們的編程語言是要能操作所有的輸入輸出,因此,API提供了兩個頂層抽象類,用來表示操作所有的輸出輸出:InputStream,OutputStream。並且,這兩個類表示字節的輸入輸出,因爲輸入輸出的本質是字節流。這裏注意體會一句話“字節流是最最基本的流”,這句話的由來就是因爲計算機底層傳遞的就是字節。那麼,當我們要操作文件的時候,就需要具體的對文件系統操作的IO實現類,於是我們需要學習FileInputStream和FileOutputStream,它們是文件輸入輸出字節流。這裏之所以FileInputStream/OutputStream作爲子類出現,按照面向對象思想理解就是,將來還有別的字節流來操作別的設備(比如將來需要通過操作網絡設備獲取網絡數據,再比如需要操作機器人,那麼或許就會再來個RobotInputStream和RobotOutputStream,這些新的需求也就都可以繼承這個體系)(這裏順便提一句架構設計思想,其中有一種設計原則叫“開閉原則”,其核心是:一個對象對擴展開放,對修改關閉。就是說,一旦寫好了某個類,就不要去輕易改動他,而是要保證它一直能運行下去,而面對新的功能需求時,只要在原有代碼上增加即可,而不是修改原有代碼。要做到開閉原則,就需要分清需求中未來哪些部分是穩定的,哪些是很可能變化的,而往往抽象的部分是最穩定的,把穩定的內容分離出來,就能滿足開閉原則。這就是爲什麼Java的類設計的如此之瑣碎,爲什麼我們要從繼承關係角度去理解JavaIO流的設計)

6,學了文件IO字節流之後,我們會發現原始的字節流對象用起來沒那麼高效,因爲每個讀或寫請求都由底層操作系統處理,這些請求往往會觸發磁盤訪問、網絡活動或其他一些相對昂貴的操作。不帶緩衝區的流對象,只能一個字節一個字節的讀,每次都調用底層的操作系統API,非常低效,而帶緩衝區的流對象,可以一次讀一個緩衝區,緩衝區空了纔去調用一次底層API,這就能大大提高效率。所以又有了BufferedInputStream和BufferedOutputSteam,他們的用法是把字節流對象傳入後再使用,也相當於把它倆套在了字節流的外面,給字節流裝了個“外掛”,讓基本字節流如虎添翼。

7,說到操作文件,就不得不提到文件的分類和編碼格式。文件分爲二進制文件和文本文件,二進制文件是用記事本打開後看不懂的,他們的編碼格式是特殊的,比如pdf文件,exe文件。記事本打開後人能看懂的只有純文本文件,我們處理文件(或者說處理任何的字節流),就免不了處理一些文本文件(或文本字節流)。如果是英語國家的人還好說,因爲他們是用的常用字符用一張ASCII碼錶就能表示得出來,用一個字節就能表示一個字母。但是顯然,對非英語國家的人來說,一個字節的大小無法表示他們所有的文字。因此,人們需要有能夠處理字符的類,或者說這個類提供一個功能:就是把輸入的字節轉成字符,把要輸出的字符轉成計算機可以識別的字節。所以,你需要兩個轉換流:InputStreamReader和OutputStreamWriter。這兩個類的作用分別是把字節流轉成字符流,把字符流轉成字節流。但是這兩個流需要套在現成的字節流上才能使用,當中用到的設計模式也就是常說的裝飾模式。當字節流被轉成字符流之後,恭喜你,你可以不必操作字節流了,而是可以用人類的方式read和write各種“文字”。

8,(那麼,我們爲什麼還要學習字節流?因爲字節流依然有它的作用範圍。首先,所有的流都是建立在字節流之上的,比如字符流。字節流或許可以讀任何字節,但是他處理不了Unicode(萬國碼),他處理不了Data流,Object流,也就是說,它做不了高級的事情,只能讀寫最原始的東西。字節流好比動物,能看,能聽,能汪汪叫,但是他不能讀書,不能寫字,不能理解更高級的知識。其次要注意的是,字符流只能用來處理文本文件,也就是隻能來處理字符,如果出來用來處理二進制文件,會帶來錯誤,所以處理二進制文件只能用字節流)

,9,還是回到文件系統,我們最常見的是和文件系統打交道,那麼針對如此常見的用途,讀取文本文件能不能用一種方便的方式呢?當然,大牛們替你想到並提供了。FileReader和FileWriter這兩個流對象可以直接把文件轉成讀取、寫入流。讓你省去了創建字節流,再套上轉換流的步驟。看看這類名起的,實際上很形象,xxxReader和xxxWriter,明擺着告訴你“閱讀和書寫”都是“人可以做的”也就是他們表示的是字符流。同理上面的InputStreamReader和OutputStreamWriter,表示的是把字節流轉成人可讀的,把字節流轉成人可寫的。因此他們的頂層抽象類:Reader和Writer,表示的是所有人類可讀可寫的字符流統稱。

10,同上面說的緩衝區的作用,再把Reader和Writer做成高效的,就需要BufferedReader和BufferedWriter,把它們套在Reader和Writer上,就能實現高效的字符流。

11,講到這裏,IO流的大概思想已經說的的差不多了,是不是覺得之前混亂的那些類,現在知道他們的作用和設計思想以後,稍稍清晰了許多呢?可以簡單的記,字節流是基礎,理論上可用於所有的輸入輸出場景,內容是文字的字節流可以通過轉換流轉成字符流,轉換流是字節流和字符流之間相互轉換的橋樑,把字節流轉成字符流,離不開轉換流,字符流是對於字符功能的增強可用來處理“文字”,操作文件系統應用範圍最廣,所以JDK提供了現成的FileXXX類,用來方便編程使用。

另外,還有許多類是“在內存裏自己和自己玩的”比如ByteArrayReader/Writer,PipedWriter/Reader,它們雖然也稱爲“流對象”但是他們的數據不出內存,所以它們的close()方法可有可無。以及其他帶有某些功能的類,比如序列化流,比如數據輸入輸出流,等等。

IO流對象的用法和作用大同小異,其使用環境和意義取決於具體需要,用到了再具體分析即可。

這裏主要介紹了JavaIO框架的設計思想,但具體底層實現細節,還需要學習JVM相關知識,以及微機原理和接口技術等等底層的課程。

手寫不易,覺得文章不錯可以關注公衆號「 凌晨四點的程序員 」一起學習

原文地址https://www.cnblogs.com/liaozuheng/p/13046873.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章