java中讀取文件時應該採用什麼編碼

Java讀取文件的方式總體可以分爲兩類:按字節讀取和按字符讀取。按字節讀取就是採用InputStream.read()方法來讀取字節,然後保存到一個byte[]數組中,最後經常用new String(byte[]);把字節數組轉換成String。在最後一步隱藏了一個編碼的細節,new String(byte[]);會使用操作系統默認的字符集來解碼字節數組,中文操作系統就是GBK。而我們從輸入流裏讀取的字節很可能就不是GBK編碼的,因爲從輸入流裏讀取的字節編碼取決於被讀取的文件自身的編碼。舉個例子:我們在D:盤新建一個名爲demo.txt的文件,寫入我們。,並保存。此時demo.txt編碼是ANSI,中文操作系統下就是GBK。此時我們用輸入字節流讀取該文件所得到的字節就是使用GBK方式編碼的字節。那麼我們最終new String(byte[]);時採用平臺默認的GBK來編碼成String也是沒有問題的(字節編碼和默認解碼一致)。試想一下,如果在保存demo.txt文件時,我們選擇UTF-8編碼,那麼該文件的編碼就不在是ANSI了,而變成了UTF-8。仍然採用輸入字節流來讀取,那麼此時讀取的字節和上一次就不一樣了,這次的字節是UTF-8編碼的字節。兩次的字節顯然不一樣,一個很明顯的區別就是:GBK每個漢字兩個字節,而UTF-8每個漢字三個字節。如何我們最後還使用new String(byte[]);來構造String對象,則會出現亂碼,原因很簡單,因爲構造時採用的默認解碼GBK,而我們的字節是UTF-8字節。正確的辦法就是使用new String(byte[],”UTF-8”);來構造String對象。此時我們的字節編碼和構造使用的解碼是一致的,不會出現亂碼問題了。

 

說完字節輸入流,再來說說字節輸出流。

我們知道如果採用字節輸出流把字節輸出到某個文件,我們是無法指定生成文件的編碼的(假設文件以前不存在),那麼生成的文件是什麼編碼的呢?經過測試發現,其實這取決於寫入的字節編碼格式。比如以下代碼:

OutputStream out = new FileOutputStream("d:\\demo.txt");

out.write("我們".getBytes());

getBytes()會採用操作系統默認的字符集來編碼字節,這裏就是GBK,所以我們寫入demo.txt文件的是GBK編碼的字節。那麼這個文件的編碼就是GBK。如果稍微修改一下程序:out.write("我們".getBytes(“UTF-8”));此時我們寫入的字節就是UTF-8的,那麼demo.txt文件編碼就是UTF-8。這裏還有一點,如果把我們換成123abc之類的ascii碼字符,那麼無論是採用getBytes()或者getBytes(“UTF-8”)那麼生成的文件都將是GBK編碼的。

這裏可以總結一下,InputStream中的字節編碼取決文件本身的編碼,而OutputStream生成文件的編碼取決於字節的編碼。

 

下面說說採用字符輸入流來讀取文件。

首先,我們需要理解一下字符流。其實字符流可以看做是一種包裝流,它的底層還是採用字節流來讀取字節,然後它使用指定的編碼方式將讀取字節解碼爲字符。說起字符流,不得不提的就是InputStreamReader。以下是java api對它的說明: InputStreamReader是字節流通向字符流的橋樑:它使用指定的 charset 讀取字節並將其解碼爲字符。它使用的字符集可以由名稱指定或顯式給定,否則可能接受平臺默認的字符集。說到這裏其實很明白了,InputStreamReader在底層還是採用字節流來讀取字節,讀取字節後它需要一個編碼格式來解碼讀取的字節,如果我們在構造InputStreamReader沒有傳入編碼方式,那麼會採用操作系統默認的GBK來解碼讀取的字節。還用上面demo.txt的例子,假設demo.txt編碼方式爲GBK,我們使用如下代碼來讀取文件:

InputStreamReader  in = new InputStreamReader(new FileInputStream(“demo.txt”));

那麼我們讀取不會產生亂碼,因爲文件採用GBK編碼,所以讀出的字節也是GBK編碼的,而InputStreamReader默認採用解碼也是GBK。如果把demo.txt編碼方式換成UTF-8,那麼我們採用這種方式讀取就會產生亂碼。這是因爲字節編碼(UTF-8)和我們的解碼編碼(GBK)造成的。解決辦法如下:

InputStreamReader  in = new InputStreamReader(new FileInputStream(“demo.txt”),”UTF-8”);

InputStreamReader指定解碼編碼,這樣二者統一就不會出現亂碼了。

 

下面說說字符輸出流。

字符輸出流的原理和字符輸入流的原理一樣,也可以看做是包裝流,其底層還是採用字節輸出流來寫文件。只是字符輸出流根據指定的編碼將字符轉換爲字節的。字符輸出流的主要類是:OutputStreamWriterJava api解釋如下:OutputStreamWriter 是字符流通向字節流的橋樑:使用指定的 charset 將要向其寫入的字符編碼爲字節。它使用的字符集可以由名稱指定或顯式給定,否則可能接受平臺默認的字符集。說的很明白了,它需要一個編碼將寫入的字符轉換爲字節,如果沒有指定則採用GBK編碼,那麼輸出的字節都將是GBK編碼,生成的文件也是GBK編碼的。如果採用以下方式構造OutputStreamWriter

OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(“dd.txt”),”UTF-8”);

那麼寫入的字符將被編碼爲UTF-8的字節,生成的文件也將是UTF-8格式的。

發佈了6 篇原創文章 · 獲贊 12 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章