當前位置:
首頁 > 知識 > Java——IO 流

Java——IO 流

導語:


打開頭條,看到自己所有的文章已經被瀏覽了125萬次的時候真的很開心,然後再看到已經有20356個粉絲的時候,更是非常非常開心,同時謝謝你們給了我繼續寫下去的動力,非常感謝。這篇文章寫一寫關於IO 流中自己學到的一些基本知識,以及遇到的問題,希望能夠幫助到大家。

1.IO 流的引入

我們可以利用 File 類將 java 程序跟硬碟上的文件聯繫起來。我們可以獲取其中某些屬性。但是,文件的內容我們不能操作,讀取。這時候就引入了 對文件進行操作的 IO 流。

Java——IO 流

IO 流示意圖

我們可以生動形象的把 IO 流當作一根根管子,管子的一端懟到目標文件,另一端懟到程序中。我們寫的程序在這裡相當於一個數據傳輸的中轉站。


2. IO 流分類

2.1 按照讀取單位劃分:


位元組流 字元流
輸入流 InputStream Reader
輸出流 OutputStream Writer

2.2 按照功能劃分

  • 節點流:直接從源文件讀取數據到程序中 —— 一根管。

  • 處理流:需要多個流結合使用 —— 多根管。

在我目前所看到的所有程序中,想要利用 IO 流,必須先用輸入輸出位元組流,或者輸入輸出字元流連接到目標文件!!!

下面主要寫一下各個流的用法。如有疑問以及不妥的地方歡迎指正,感激不盡!

3. 位元組流--FileInputStream,FileOutputStream

3.1 文件 ---> 程序(以程序為主體,對於程序來說屬於對內輸入,所以要用輸入流)

3.1.1 利用單個位元組

Java——IO 流

首先要確定被讀取文件的地址(代碼第 4 行),然後創建一根管(就是 IO 流),一端懟到該文件上去,另一端懟到程序中,進行吸的動作(也就是程序讀取文件)。(怎麼樣,理解的還可以不,哈哈)

從上面的代碼第 8 行和第 11 行可以看出 這種方法是一個位元組一個位元組的將文件中的信息讀入到程序中。

缺點:

  • 運行結果會出現亂碼;

  • 一個位元組一個位元組讀取 ,效率太低;

3.1.2 利用數組緩衝區

Java——IO 流

這種方法是定義了一個數組(第 8 行)8個位元組,通俗一點說,就是每 8 個位元組為一組進行讀取,用數組將文件中的信息讀入到程序中,效率比比上一種方法高。

3.2 程序 ---> 文件(以程序為主體,對於程序來說屬於對外輸出的,所以要用輸出流)

3.2.1 利用單個位元組

Java——IO 流

首先要確定要把文件讀取到哪兒(代碼第 4 行),然後創建一根管(就是 IO 輸出流),一端懟到該文件上去,另一端懟到程序中,進行吐的動作(也就是把內容從程序中寫出去)。因為位元組輸出流只能一個位元組一個位元組的向外讀取,所以要調用 String 的 getBytes() 方法將 String 類型數據准換成 byte 類型,而該方法返回值為一個 byte 類型數組。

3.2.2 利用緩衝數組

Java——IO 流

定義了一個數組(第 10 行),調用 String 類型的 getBytes() 方法,將字元串轉化為位元組,用一個數組接住該方法的返回值。然後再用循環遍歷將數組中的信息讀取到文件中,效率比比上一種方法高。

一定要記得關流!!!

3.3 文件的複製

3.3.1 利用單個位元組進行複製

Java——IO 流

功能:就是利用輸入輸出位元組流,一個位元組一個位元組的將 i:/test/haha.txt 文件中的內容複製到 i:/test/demo.txt 中去。

程序相當於一個中轉站(開篇的 IO 流示意圖),利用位元組輸入流(FileInputStream)將 haha.txt 中的內容讀取到程序中,然後利用位元組輸出流(FileOutputStream)從程序中寫出到目標文件 demo.txt.

3.3.2 利用數組緩衝區

Java——IO 流

功能:定義了一個數組(第 10 行)8個位元組,每 8 個位元組為一組進行讀取,FileInputStream 利用數組將 haha.txt 中的信息讀入到程序中(第 11 行),其中 len 表示這個數組中被佔用的數量,當讀取到文件結尾的時候 len = -1(這是規定,我也不知道為啥是 -1 ,不是其他的數字,這個記住就好。。。);然後 FileOutputStream 把程序中讀取到的信息寫入到目標文件中(第 14 行)。


4. 字元流--FileReader,FileWriter

  • 和位元組流一樣,用字元流進行文件的複製也分為兩種方法,一種是利用單個字元進行讀取和寫出,另一種是利用數組進行讀取和寫出。

4.1 利用單個字元

Java——IO 流

  • 功能:和 3.3.1 中一樣,只不過是利用字元流來進行操作。

4.2 利用數組緩衝區---char[]

Java——IO 流

  • 功能:和 3.3.2 類似,只不過是定義了一個字元數組(代碼第 10 行)進行讀取和寫出操作。

另外要說明的是:用字元流複製非純文本的文件都是不行的,都是耍流氓!因為用字元流複製的時候,它會按照系統的字元碼錶進行查找和替換,把二進位數據全部按照碼錶替換了,但是圖片的一些代碼能在碼錶中找到相對應的編碼,就轉換成編碼,另外還有一些找不到,JVM就會用類似的編碼代替,那麼你再打開的時候就肯定不是圖片了。

總之,記住千萬不要耍流氓啊!!


5. 緩衝位元組流--BufferedInputStream,BufferedOutputStream

先上圖(以下圖都是按照個人理解畫出來的,如有錯誤還請指正):

Java——IO 流

位元組流複製文件原理

我們上面寫的代碼都是利用位元組流進行文件的複製。以上圖為例,每次讀取或寫出都會對硬碟上的文件訪問一次,缺點就是對硬碟的訪問次數太多,對硬碟來說這是有害的。這時,就可以利用緩衝位元組流。

再上圖:

Java——IO 流

緩衝位元組流複製文件原理

根據下面的代碼來理解一下這張圖:

Java——IO 流

程序解釋:先創建輸入位元組流 fis (第 7 行)懟到目標文件(i:/test/haha.txt),然後創建緩衝位元組流 bis(如圖紅色),bis 套在 fis 上使用(相當於一根管子上套了另一根管子)。使用緩衝流會有一個緩衝區,fis(位元組輸入流)會儘可能多的把源文件中的數據讀取到緩衝區,然後 bis 再利用緩衝數組從緩衝區中每 8 個位元組為一組的讀取。寫出的過程和讀取的過程正好相反就不在此贅述啦。(如果還不理解可以留下評論)

這種方式屬於一根流套在另一根流,也就是管套管。上使用這樣的話就減少了對硬碟的訪問次數。


6. 緩衝字元流--BufferedReader,BufferedWriter

緩衝字元流和上面的緩衝位元組流的運行原理一樣,只不過一個使用位元組流,一個使用字元流而已。

Java——IO 流

這種方式也是屬於管套管來操作數據,效率比上面的緩衝位元組流要高(因為使用的是字元流)

之前操作數據,要麼是一個位元組一個位元組的讀取,或者是一個數組一個數組的讀取。那麼下面介紹一種效率更高的方式:一整行一整行的讀取數據。

Java——IO 流

程序其他部分不變,只是讀取的方式不一樣。


7. System對 IO 的支持

在這裡補充一下,我們寫程序的時候經常會用到鍵盤輸入這個語句:Scanner sc=new Scanner(System.in);

那麼我有沒有考慮過鍵盤輸入這件事到底是誰來完成的呢,是 Scanner 還是 Sytem.in ?

其實,鍵盤錄入這個功能是由 System.in 來完成的,Scanner 只是起到一個掃描器的作用。System.in 會返回一個 InputStream 類型的變數,也就是返回一個流。那麼Scanner sc=new Scanner(System.in);這條語句可以通俗的理解為有一個掃描器 Scanner,一個鍵盤,它們倆之間是用一根管子(流)連接起來,鍵盤錄入的數據通過這根管子傳進掃描器中。

還有一個比較坑的地方,寫出來給大家做個提醒:

Java——IO 流

代碼第 5 行中,in.read(b) 按理說返回結果為 b 被佔用的長度啊,那麼,我輸入數字 1,結果輸出 3,也就是說,佔用了 3 個位元組!哇,當時整的我很鬱悶,不就佔用了一個位元組嗎,應該是 1 才對嘛。

後來才搞清楚,運行這段代碼的時候,你輸入 1 之後,按下了 Enter 鍵,也就是輸入完數據之後進行了回車、換行,而回車和換行在 ASCII 表中對應的數值分別是 13 和 10,它們倆又各佔了一個位元組,所以是佔用了 3 個位元組,輸出結果為 3。不知道我有沒有表達清楚?

  • 補充一點:位元組流轉化為字元流

Java——IO 流

這段代碼中,主要想表達的就是第 6 行,將位元組流轉化為字元流,其他的就是和之前的代碼差不多,都是讀取寫入。


8. 數據流--對基本數據類型處理--DataInputStream,DataOutputStream

8.1 將基本數據類型的東西輸入到目標文件中去:

Java——IO 流

代碼第 3 行是將各個需要的流套在一起直接一句代碼寫出來了,應該能看懂吧。

執行完這段程序之後如果打開目標文件,將會看到...亂碼,哈哈。別慌,因為這是給程序看的,咱可能看不懂的。那麼要是想看該怎麼辦呢?有辦法,在一個程序中執行下段代碼:

Java——IO 流

這段代碼是為了將文件中的內容寫入到程序中,然後在控制台輸出。第一句不用解釋了吧。而且,重要的是寫進文件的順序和讀到程序中的順序必須一致!就是說,假如你寫進文件的第一個是 int 類型的,那麼輸出的第一個也必須是 int 型的,這樣一一對應才能保證不出錯。


9. 對象流--對引用數據類型處理--ObjectInputStream,ObjectOutputStream

9.1 放入String 類型數據:

Java——IO 流

這段代碼就是將 「java」 寫到目標文件中去。

9.3 現在要寫入 Person 的一個對象:

假如說我自定義了一個 Person 類。,然後我現在要把一個 Person 類型的對象放進目標文件中去,按照上面的放 String 類型數據的方法:

Java——IO 流

這段程序運行結果如下:

Java——IO 流

運行結果

發現出錯了,「NotSerializableExeption」,啥意思呢,就是說Person 類沒有序列化!!

那麼怎麼解決呢?方法:實現 Serializable 方法,加序列號。

Java——IO 流

調試方法

謹記:以後如果要對類的對象進行網路傳輸一定要實現序列化!!!



如果您能看到這裡,我真的表示萬分感謝,這篇文章如果有什麼錯誤的地方,或者您不理解的地方,歡迎留言。另外我有這部分學習的視頻,如果需要的話,也可以來團長的群里,我分享給您。就這樣,謝謝各位!


學習Java的同學注意了!!!

學習過程中遇到什麼問題或者想獲取學習資源的話,歡迎加入Java學習交流群495273252,我們一起學Java!

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Java團長 的精彩文章:

Java開發中如何正確踩坑?
《實戰java高並發程序設計》源碼整理及讀書筆記
JavaSE的自動裝箱和自動拆箱
程序員如何選擇未來的職業路線

TAG:Java團長 |