java中IO及中文亂碼問題

第一次發這種博客,因此一直在糾結怎麼開頭,乾脆直奔主題吧,把本身的一些總結體會記錄下來,先從簡單的學習開始,但願能夠慢慢堅持,之後的內容能夠寫的更好更有意義。java

其實真正在工做中中文亂碼的問題遇到的很少,那是由於公司爲了開發方便因此文件都統一編碼了。可是我以爲還有頗有必要去稍微瞭解一下其原理的。設計模式

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中提供了字符流對象,即在字節流的基礎上加上對編碼的設置,達到解決亂碼的問題。jvm

廢話很少說,用幾個小案例來講明一下:學習

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();3d

b,採用字節流code

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來嘗試一下,觀察字符串在編譯和運行時的字節碼及編碼問題。

相關文章
相關標籤/搜索