標籤:read output 設計 構造 內容 匿名 images 自己的 存放裝置
第一次發這種部落格,所以一直在糾結怎麼開頭,乾脆直奔主題吧,把自己的一些總結體會記錄下來,先從簡單的學習開始,希望可以慢慢堅持,以後的內容可以寫的更好更有意義。
其實真正在工作中中文亂碼的問題遇到的不多,那是因為公司為了開發方便所以檔案都統一編碼了。但是我覺得還有很有必要去稍微瞭解一下其原理的。
IO就是輸入輸出資料流,用物件導向來理解的話,就是輸入,輸出資料流對象,主要用來操作檔案對象。所以再稍微談談檔案的概念,即File對象。在Java中,File不是我們平時生活中指的某個具體檔案,而是某個路徑對象,比如說 File file=new File("D:\\aaa"); 這就是一個File對象,也許它表示的是一個檔案夾,也許這個路徑都不存在,但是這句代碼就的的確確建立了一個表示該路徑的File對象。這種寫法只是不常用罷了。因為我們平時可能更多的是操作一個文本,圖片等等,如File f=new File("aaa.txt");
上面簡單說了IO,File是什麼,接下來再談談這些圖片,文字,視頻等資訊是如何儲存在我們存放裝置上的。個人理解是不管是什麼類型的檔案,都是二進位的形式儲存,最小單位是1個byte,即8位01組成。所以說我們假如要拷貝一個檔案,只要操作位元組流就好了,即把一個檔案中的所有位元組拿到,寫到另一個檔案中就OK了,其實理論上是可以的,但是對於字元型的檔案比較特殊。這也就是為什麼會有中文亂碼的問題出現。ASCII碼錶大家都很熟悉,起碼都聽說過,它應該算是很早出現的一種碼錶了吧,起初只是用來表示26個英文字母和一些特殊符號(因為電腦只識別二進位,所以要把字元用相應的位元組來代替,形成一張碼錶)。但是隨著電腦的發展,ASCII應該不夠用了吧,而且很多國家應該也都有自己的一套編碼方案,所以就出現了不同的編碼錶。常見的有GBK,UTF-8,而jvm中預設使用的是unicode編碼,即以2個位元組表示一個漢字,UTF-8則不一定,可能3個位元組表示一個漢字,也可能更多。所以就出現了一個問題,同一個漢字在不同的碼錶中對應的位元組碼的個數和內容都不相同。所以如何解決?
我們從A磁碟上拷貝一張圖片到B磁碟上,只要把A的所有位元組拿到B就可以了。但是同樣的方式操作一個文本其實也是可以的,前提是A和B中的文本編碼要相同。因為圖片不存在位元組編碼的問題。但是我要從網路上或者伺服器去傳輸中文怎麼辦呢,肯定不能單單通過位元組來實現了(因為我們不可能遇到問題就手動去變更檔的編碼方式吧)。所以java中提供了字元流對象,即在位元組流的基礎上加上對編碼的設定,達到解決亂碼的問題。
廢話不多說,用幾個小案例來說明一下:
1,首先在當前項目下建立aa.txt,bb.txt。隨便在aa中寫幾個中文字元。會發現這兩種方式都可以實現
a,採用字元流
FileReader fr=new FileReader("aa.txt");
FileWriter fw=new FileWriter("bb.txt");
int c;
while((c=fr.read())!=-1){
fw.write(c);
}
fr.close();
fw.close();
b,採用位元組流
FileInputStream fis=new FileInputStream("aa.txt");
FileOutputStream fos=new FileOutputStream("bb.txt");
int b;
while((b=fis.read())!=-1){
fos.write(b);
}
fis.close();
fos.close();
2,此時假如aa的編碼方式是UTF-8的話,那麼我們把bb的編碼改為GBK看看,同樣運行上面兩種方法,全部亂碼。
原因就是由於兩個檔案的編碼方式不同,導致中文查的碼錶不同,所以亂碼。
3,所以當兩邊檔案的編碼方式不同,我們可以在讀取和寫入的時候都指定與其檔案對應的編碼即可。
實現方式如下:
InputStreamReader isr=new InputStreamReader(new FileInputStream("aa.txt"),"utf-8");
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("bb.txt"),"gbk");
char[] arr=new char[1024];
int len;
while((len=isr.read(arr))!=-1){
String s=new String(arr,0,len);
System.out.println(s);
osw.write(s);
}
isr.close();
osw.close();
代碼雖然很簡單,還是簡單的解釋一下,從API中可以發現InputStreamReader和OutputStreamWriter都是操作字元的對象,繼續Reader和Writer。
主要用來把位元組轉成字元,字元轉成位元組。所以從構造中也可以發現,傳入的是位元組流對象。以utf-8去讀取位元組流轉成字元,再將字元以gbk編碼轉成位元組寫入。
下面幾行就不做解釋了,都是基礎裡面的方法。構造中傳入的是匿名內部類對象,還有裝飾設計模式,這種寫法簡單瞭解下即可。
關於位元組流和字元流其實還有很多很好用的類,比如BufferedInputStream,BufferedReader等等,再次不做贅述。
關於jvm和系統平台的編碼問題,在次不做解釋。
可以用String來嘗試一下,觀察字串在編譯和運行時的位元組碼及編碼問題。
java中IO及中文亂碼問題