IO流第六課轉換流
這節課來講講轉換流
在講轉換流之前了,我們先講講字元的編碼與解碼。
首先,我們知道計算機裡所有資料都是以二進位制的形式儲存的,.java檔案想要執行必須先被編譯成.class位元組碼檔案,這裡我們提到了一個詞,位元組碼,或者說位元組,以往一直沒機會,這次就來帶大家看看位元組碼檔案。
這些以.class為字尾名的檔案就是.class檔案,這些檔案的內容全是位元組。我們開啟來看看
看不懂,對不對?我也看不懂,因為這是給計算機看的。
人看的懂的是字元,計算機能看懂的是位元組,那麼如何將計算機看得懂的位元組變成人看得懂的字元呢?又如何將人看得懂的字元變成計算機看得懂的位元組呢?
編碼:
將字元轉換成位元組的過程叫編碼,編碼指按照一定的規則將字元轉換成位元組
解碼:
將位元組轉換車字元的過程叫解碼,解碼值按照一定的規則將位元組轉換成字元
下面來看一段java程式碼
看介紹裡可以看出String 的構造器可以對位元組進行解碼,而且可以按照指定的字符集進行解碼
說一下字符集: 就是一種編碼或者解碼的規則,常見的字符集有: GBK,gb2312,UTF-8(這個我們以後用的最多)
String 可以解碼,自然也提供了編碼的方法,就是使用getBytes方法。
Demo 01:
public static void main(String[] args) throws UnsupportedEncodingException { //先來new一個byte陣列 byte[] bytes = "我愛java".getBytes("UTF-8"); String str =new String(bytes, "UTF-8"); System.out.println(str); }
輸出:
Java
注意: 如果編碼字符集和解碼字符集不相同的話,會出現亂碼
Demo 02:
public static void main(String[] args) throws UnsupportedEncodingException { //先來new一個byte陣列 byte[] bytes = "我愛java".getBytes("UTF-8"); String str = new String(bytes, "GBK"); System.out.println(str); }
輸出:
鎴戠埍java
順便一提:如果字符集不同的話,只有不在0-127之間的字元才會出現亂碼
接下來看看亂碼的第二個原因: 位元組不完整
首先有一個問題,把一個字元轉換成一個位元組陣列,那麼這個位元組陣列的長度是多少?
Demo 03:
public static void main(String[] args) throws UnsupportedEncodingException { byte[] bytes = "1".getBytes(); System.out.println(bytes.length); //1 bytes = "a".getBytes(); System.out.println(bytes.length); //1 bytes = "我".getBytes();
System.out.println("我".length()); //1 System.out.println(bytes.length); //3 }
結論: 0-127之間的字元轉位元組一個字元對應一個位元組,中文的一個漢字對應3個位元組,而且,一個漢字只是一個字元
Demo 04:
public static void main(String[] args) throws UnsupportedEncodingException { byte[] bytes = "我".getBytes(); String str = new String(bytes,0,1); System.out.println(str); //亂碼 str = new String(bytes,0,3); System.out.println(str); //正常 }
結論: 亂碼的第二個原因: 位元組不完整
OK,講清楚編碼和解碼之後,我們再來講講轉換流 。
轉換流: 將位元組流轉換成字元流的流,主要作用是處理字元編碼
轉換流常用的兩個類: InputStreamReader, OutputStreamWriter
InputStreamReader:
InputStreamReader 是位元組流通向字元流的橋樑:它使用指定的 charset 讀取位元組並將其解碼為字元。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺預設的字符集。
構造器:
主要用最後一個 InputSteamReader(InputStream in, String charsetName)
下面來看一個小例子:
Demo 05:
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException { //這裡我麼有異常直接丟擲,就不捕獲了,方便看 // BufferedReader reader = new BufferedReader(new FileReader(new File("F:\\code\\java\\2.txt"))); //這裡我們就發現了一個問題,我們在用字元流讀取檔案的時候,沒辦法指定字符集編碼,這是有很大問題的 //因為編譯器的預設編碼可能和檔案的編碼不一樣,這樣就會造成亂碼的現象 //所以我們希望能指定編碼,同時又去用字元流去讀取(加緩衝流是提高效率),這個時候就需要轉換流 //轉換流有兩個: InputStreamReader, OutputStreamWriter //這樣我們就可以使用指定字符集編碼的字元緩衝流來讀取檔案了,看起來有點麻煩,實際上了解了原理以後非常的好寫,我們來重新寫一遍 /** * 第一步 new一個BufferedReader,構造器需要一個Reader型別的引數 * 第二步 由於轉換流InputStreamReader是Reader的子類,所以可以把InnputStreamReader物件 傳進去 * 第三步 InputStreamReader需要一個InputStream 和 一個 字串(表示字符集編碼) */ BufferedReader reader = new BufferedReader( new InputStreamReader(new FileInputStream(new File("F:\\code\\java\\2.txt")), "UTF-8") ); //這樣,一個可以指定字元編碼集的字元 緩衝流就構造好了,剩下的就和以前講的一樣即可 //OutputStreamWriter和InputStreamReader差不多,只不過一個讀,一個寫 BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(new File("F:\\code\\java\\3.txt")),"UTF-8") ); }