java零基礎入門-高級特性篇(十一) IO 流 1

IO的故事可以從2000多年前的始皇帝開始講起。自從秦始皇統一六國以後,書同文,車同軌,統一貨幣度量衡,簡單的說就是制定了一個統一的標準。而與本章有最大關係的就是「書同文」了。正是由於秦始皇統一了文字,所以今天不論是書籍還是網路,都有統一的文字標準,但是可惜的是,這個統一的標準只在國內是統一的。由於互聯網將全世界的距離縮小到了你與屏幕的距離,這時候問題就出現了。

編碼的故事

計算機是二進位的世界,而我們的世界卻有著各種各樣的語言,如果要將一篇文章存在計算機的硬碟上需要做什麼?不僅僅是文章的保存,只要是需要藉助計算機才能完成的工作,比如將一篇文章發到各個網站,或者通過通訊軟體發給朋友,都會有一個過程,就是將人類語言轉變為計算機的語言,這個過程就是編碼。那麼怎麼將人類語言轉為計算機語言呢?其實這個問題給你,你用不了多久就會想到辦法。

辦法

是不是這樣?既然計算機只認識數字,把英文和數字對應起來不就可以了么。但是這裡用的十進位,而計算機只認識二進位,那就將十進位換為二進位就可以 了。還有一個問題,其實除了英文字元,還有很多其他的符號,符號在計算機中也有很大的作用,按照這樣的思路,第一代的編碼規範 ASCII 編碼就橫空出世了。搞計算機的大佬個個都是天才,他們想的比你快,比你更全面。大佬掐指一算,符號加字母,128個不多不少剛剛好。為什麼是128個?

對照

看看二進位的表示,0000 0000到0111 1111就是從0到127一共128個數,正好8位1位元組(1個位元組8位),正好一個位元組全部搞定,大佬就是大佬。上圖中是ASCII表中需要有印象的幾個特殊字元。第一個是空字元,編號0,數字1編號49,大寫字母A編號65,小寫字母a編號97,最後一個表示delete。

這個ASCII表是美國人發明的,所以表中只有字母和數字,因為對於美國人來說,這些就夠了。但是歐洲人一看就發現問題了,光這幾個字元不夠用啊,比如念個電話號碼比讀一篇文章還難的法語,不練好舌頭的震動就不會發音的德語,於是歐洲人弄了一套ISO-8859-1字元標準出來,滿足了自己的需求。美國歐洲都有了自己的標準,我們也必須有自己的標準啊。中華文明博大精深,中文常用字就有幾千個,加上不常用的怎麼也得有幾萬,這怎麼辦?先把常用字弄出來,於是GB2312就出現了。後來為了完整的包含中文,將GB2312擴展了2次,第一次擴展後叫GBK,第二次擴展後叫GB18030。

編碼

好了,看到不同的地區有自己的編碼,各個國家玩的遍地開花,不弄個自己的標準都不好意思出門跟人家打招呼了,然後世界就亂了。美國人用ASCII編碼發了個郵件給韓國人,韓國人用自己的編碼打開一看,全是亂碼,標準不同無法轉換。怎麼辦?那就來個國際標準統一全世界唄,這就有了Unicode編碼,有了Unicode,發郵件再也不亂碼了。

但是互聯網的高速發展,希望有比Unicode更優秀的編碼出現。因為Unicode包含了全世界所有的文字,那麼它的範圍肯定非常大,甚至需要4個位元組來表示,但是如果是一篇美國人寫的文章,用Unicode來編碼,就會發生一個位元組搞定的字元結果用了2個甚至4個位元組來表示,浪費很多空間。

最後,最重要的編碼方式登場了,大家請記住他的名字 UTF-8。UTF-8繼承了Unicode涵蓋的所有字元,並且將長度變成了可變長。如果是美國人寫的文章,用1個位元組保存字元即可,如果是中國人的文章,用2個位元組保存字元,並且都是UTF-8的編碼方法,即節約空間,又統一編碼。我們在web項目中使用最多的也就是UTF-8編碼。

下圖是同一個文件分別用Unicode和UTF-8編碼後的大小。可以發現使用UTF8編碼的文件佔用空間小了一半。

不同編碼

最後用一個圖來概括一下。

總結

看了上面這麼多編碼,真的是需要感謝始皇帝統一了中國,不然我們國內還有一堆編碼,各種方言編碼,那簡直就是災難啊。但是,這跟IO流有什麼關係?

IO流是什麼

首先明確一個知識點,計算機是二進位的世界,所以在計算機上存儲的文件都是byte位元組儲存。而在計算機內,存儲的文件可以分為兩大類,一類是文字類型的文本,另外一類是各種媒體類型等,如果直接使用文本來打開這些文件,裡面全是亂碼,只有特定的軟體才能打開。比如播放器打開視頻文件,圖片軟體打開各種圖片。

針對這兩種文件,java有兩種IO流對應他們,那就是位元組流和字元流。上面說過在互聯網時代,使用UTF-8編碼傳輸文件可以減小文件體積,加快傳輸速度,但是在計算機本地,使用Unicode編碼較多,java虛擬機為了在全世界的機器上使用,所以它使用的是Unicode編碼方式,而且是將位元組轉為字元,以方便支持各個國家的語言,所以如果要對文件進行編碼使用字元流。如果不需要編碼,則使用位元組流,因為除了文字之外的文件,不需要我們看得懂他們的編碼是什麼,需要使用他們的時候有特定的軟體對文件進行轉碼。

文本打開圖片

用文本打開圖片是上圖的樣子,這不是我們需要的,所以看圖片使用圖片軟體即可。

說了這麼多,IO流到底是什麼還是不懂,別急,這就說。

首先看IO,IO對應Input/Output首字母,表示輸入和輸出。流又是什麼呢?既然文件都是以位元組存儲,那麼進行輸入,輸出的時候就是按照位元組來傳輸,文件變成了一串數字,源源不斷的從一個地方到另一個地方。比如複製文件的時候,經常會看到一個進度條,在這個進度條背後計算機在幹什麼呢?他在一邊讀文件,一邊寫文件,讀的時候將文件用01011101的方式讀出來,寫入的時候,又將文件以01011101的方式寫入到磁碟,看上去就像水流一樣,源源不斷。

注意這裡最小單位是位元組,就是8位,比如01011101就是一個位元組,最小的傳輸單位。

複製文件

文件傳輸完成之前,這個文件是打不開的,只有傳輸完成後,才是一個完整的文件,可以用軟體打開。計算機內的文件傳輸,這就是IO流。除了計算機內部的傳輸,計算機還可以從遠程伺服器上通過網路讀取文件,寫入硬碟,這種方式也是通過IO流實現。

java中的IO流

java中的IO流體系比較龐大,涉及到很多類,但是常用的其實並不多,所以本文只會介紹最常用的部分。學會了常用的,其他的各位可以參考java的API,理解起來沒有難度。下面來介紹一下java中的IO流體系。

體系

IO流主要分為兩大類,一種是字元流,用來對文件進行編碼,輸出人類可以看懂的文字。另一種是位元組流,用來傳輸各種軟體可以識別的文件。每一大類都擁有輸入和輸出的功能,所有輸入的字元流的父類叫做Reader,所有輸出的字元流的父類叫做Writer。對應到位元組流,所有輸入的位元組流的父類是InputStream,所有輸出的位元組流的父類是OutputStream。這幾個父類按照分類和輸入輸出的功能來記憶會方便很多。

以上四個類都是抽象類,為什麼要使用抽象類?回憶一下前面的知識,抽象類用來定義子類的公共功能,還可以留下一部分抽象方法,到子類再來實現,這樣不同的子類就可以有不同的功能了。比如上圖右側標識出了四種功能,分別是「帶緩衝功能」,「位元組與字元轉換」,「位元組操作文件」,「字元操作文件」,如果不使用抽象類,可能每一個類中都會有一堆重複的功能,也就是在抽象類中已經實現的功能,他們會重複的出現。而使用抽象類以後,每個子類只需要實現抽象類中的抽象方法即可。

繼續觀察上圖,會發現最終用來操作字元流的類是FileReader和FileWriter。如果需要緩衝功能,可以使用BufferedReader和BufferedWriter。而最終用來操作位元組流的類是FileInputSteam和FileOutputStream,如果需要緩衝功能,則使用BufferedInputStream和BufferedOutputStream。發現沒有,其實最終最重要的8個類就是字元和位元組的輸入和輸出各一個,他們分別還有一個帶緩衝功能的類,根據情況選擇使用不同的類。

下一章再來具體介紹上面8種類的使用方法。

推薦閱讀:

相关文章