繼續,順着《Java學習里程-----Java基礎_23 Java IO 流(一)》這個,接着來
六、字節流
(先打開Java Api開發手冊,沒有的同學 -> https://docs.oracle.com/javase/8/docs/api/ )
字節流中,輸入流的祖類,InputStream
這個是一個抽象類,無法直接實例化,只能實例化他的子類。它的子類有(看 Direct Known Subclasses 的下面)
是吧,子類很多的,而且這個InputStream還實現了Closeable接口,這個我們後面再去說這個Closeable接口。
輸出流的祖類是 OutputStream,同樣搜索一下
是吧,同樣也是一個抽象類,它下面的子類也有很多,但是不如InputStream多,多不多沒有啥關係,無所謂的。
瞭解了一下字節流的類之後,我們可以寫個demo進行測試測試。
七、InputStream
我們剛纔說過,InputStream是一個抽象類,需要由子類來進行具體的實現,我們先使用FileInputStream來實現一下。
打開eclipse,我還在我原有的Test工程上進行編寫。(當然這樣的做法是不對的,我建議大家自己創建一個新的類,然後進行代碼的編寫,不要養成習慣,每次Test,每次Test,這樣不好,而且到時候你找代碼的時候你都找不到。)
我們可以看到啊,在使用FileInputStream這個子類的時候呢,有三種方式進行實例化,各有各的不同。
第一種是傳一個file,我一般都用這個。第二種傳入一個FileDescriptor 類型的參數,說實話,我沒有用過第二種這個。第三種是傳入一個文件路徑即可,這個也可以,但是也不是常用。我個人傾向於第一種,傳入一個file。但是這裏我們三種都會講述。
雖說這個是字節流,但是因爲我們的輸出窗口弄不出來圖片顯示,所以我們就不弄圖片了,我們弄一段文字來測試一下,大家在自己的桌面上創建一個txt的文本,當然,不帶要弄得話,我下面會上傳一下這個附件,我們來讀取一下里面的內容,內容的話中文英文無所謂,文件名也是中英文無所謂。
我們來讀取一下桌面上的這個txt文件
進來就能看到這個課件,直接下載就好
第一種方法:我們先來用傳入一個file的構造器來構造FileInputStream
先創建一個File,然後給一個文件地址。
文件地址,在txt鼠標右鍵,最後一個屬性,自己查看。
注意啊,實例化File這個類的時候用的 java.io.File 下面的File,別導入錯了包。
然後實例化InputStream。這裏會有異常,我們來捕獲一下異常。
然後怎麼讀取文件裏面的內容呢?
我們用 inputStream.read() 去讀取內容。
我們點進去可以看到,讀完之後會返回一個int類型的值,這個就是一個二進制的數字,我們用一個int類型的變量去獲取上這個值。(這裏還得捕獲一下異常)
現在我們輸出一下這個i,我們先來看一下是什麼。
輸出了一個229.
很明顯啊,不對,因爲這個229我們文本里面沒有,二呢,我們也不知道229是對應的什麼。這裏我們看一下源碼是怎麼描述的
鼠標指針指導read,按ctrl ,然後鼠標左鍵點進去。或者你直接從api中查找。找到直接Google翻譯一下。
這段話說的是這個read方法,從輸入流中讀取下一個數據字節。等到讀讀讀,讀到-1的時候,說明就讀取完成了。so,我們需要用到循環,將這個讀取出來。我們修改一下代碼
如果讀取到的東西不是-1,我們就一直讀取,然後將讀取之後的數字我們存放到一個byte數組中。
這樣,然後我們輸出,輸出什麼呢,將這個b進行轉換,轉換成String類型。
寫到這裏爲止,我們可以看到一個感嘆號,我們不要管這個感嘆號,我們先運行。
很好報錯了,報錯的原因是什麼呢?
我們移動到這個b 上面,它的意思是說:這個b 不能是空的去運行,需要給一個初始值。我們這裏給他弄好初始值,給它1024個單位。
再來運行。
我們會發現還有錯誤,這個錯誤是說,我們其實後面還在讀取,但是你的這個byte存放不下了,導致len++這個數字已經超過了1024,byte但是最大也就1024個空,沒有多的了,所以報錯了,這個我們給大一點byte數組的長度。我給成2048,試一下。
是OK的,沒問題,讀取出來了,但是,新的問題又來了,不要慌,我們來分析一下爲什麼。
首先,一箇中文呢是兩個字節。而我們在使用InputStream讀取的時候是按照一個字節一個字節去讀取。
找到問題之後,我們來想辦法解決。
System.out.println(new String(b, "utf8")); 我們只需要再輸出的時候按照utf8的格式去輸出就好。
除去這樣的寫法之外,還有一種是直接創建一個byte數組,然後read,傳入這個byte輸出,最後將byte數組轉換成String類型進行輸出。
我很喜歡這樣的方式,當然,上面的方式也可以,這個大家自己選擇,比較條條大路通羅馬嗎。
上面的就是一個字節一個字節的去讀取,下面是一起讀取,就這點差別。我們來測試一下長一點的文本,我們來看一下用的時間是多少,因爲後面我們要會和字符流進行對比。
long start = System.currentTimeMillis();
我們用這個來獲取一下開始時間。
long end = System.currentTimeMillis();
這個獲取結束時間,這兩個時間都是long類型,我們到時候一算差就知道花了多久了。
我換一個文本進行讀取,找一個比較長的。
不幸的是,這個文章也不怎麼長,我這裏本地讀取也就3~4毫秒就OK了。
我們再看一下另外一個方法。
32 ~ 44 毫秒之間,說明,一起讀取要比這個一個一個讀取快。
so 我們推薦整體讀取。
第二種方法:我們再來用傳入一個String的構造器來構造FileInputStream
這樣也是可以的,其實。我們可以看一下源碼。
它底層其實還是弄了一個file,只是我們調用的人看不到而已。
第三種方法:最後一個方法,我們用傳入FileDescriptor的構造器來構造FileInputStream
我明說,搞不懂,屬實不會,有興趣的同學自行研究,我是從事Java開發到現在,沒有用到過。我個人建議,會用好上面內兩個就OK了。
八、關閉流
其實,我一直都沒有說這個問題啊,在我們學習這個流的過程中,有很重要的一步,就是關閉流。因爲流再開啓的時候,你要是不關閉,這玩意是很耗內存的,就像水龍頭,用完要記得關閉,忘記關那得浪費多少水啊。
所以,我們需要在catch之後的finally方法中加一個
切記 一定要加!!!不管是字符流還是字節流,輸入流輸出流,用完一定要關閉。!!!
一定要關閉!
我們這節就講到這裏,下一節我們開始說OutputStream。記得點點關注,小心心。
課件大家自己去下載哦。