前段時間寫的
深入淺出Java中文問題系列描述了很多Java各種應用中出現(xiàn)的中文問題,唯獨沒有說到文件的讀寫。最近用Java處理文件的時候,同樣遇到了中文問題,覺得還是有必要總結一下,也使該系列的文章更加完整。
??? 熟悉Java 的人都知道,在Java中,IO是分成兩大部分的,分別對應字節(jié)和字符的操作,也就是Stream和Character,它們之間可以相互轉換,橋梁就是StreamInputReader/StreamOutputWriter。為了更加清楚的了解它們之間的關系,我們可以看看它們所在的類結構。
java.lang.Object - java.io.InputStream (implements java.io.Closeable)
- java.io.OutputStream (implements java.io.Closeable, java.io.Flushable)
- java.io.RandomAccessFile (implements java.io.Closeable, java.io.DataInput, java.io.DataOutput)
- java.io.Reader (implements java.io.Closeable, java.lang.Readable)
- java.io.BufferedReader
- java.io.InputStreamReader
- java.io.Writer (implements java.lang.Appendable, java.io.Closeable, java.io.Flushable)
- java.io.BufferedWriter
- java.io.OutputStreamWriter
上面列出來的并不是Java.io中全部的類,但是對于文件讀寫來說已經足夠了。通常,我們使用以下代碼來進行文件的讀寫:
public void naiveWrite() throws IOException{
? FileWriter fw = new FileWriter("test.txt");
? fw.write("中文你好");
? fw.close();
}
public String naiveRead() throws IOException{
? FileReader fr = new FileReader("test.txt");
? BufferedReader br = new BufferedReader(fr);
? String str = br.readLine();
? br.close();
? fr.close();
? return str;
}
?? 如果我們的是中文平臺,上面代碼是可以正常運行的。但是如果我們把這些代碼放到一個ISO8859-1的系統(tǒng)上,中文問題就出來了(當然,前提你在javac的時指定了編碼方式,如javac -encoding gb2312 ***.java,參看該系列前面的文章)。為什么呢?這是因為FileWriter和FileReader是輔助類,為了方便大家使用 OutputSteamWriterer 和 InputStreamReader 而屏蔽了字符集的設定操作,而采用系統(tǒng)默認的編碼方式,而這在很多情況下也能滿足用戶的需求。在中文系統(tǒng)中,系統(tǒng)的默認編碼方式一般是GBK,因此文件中中文的讀寫是沒有問題的。但是,當程序運行在ISO8859-1的系統(tǒng)中時,JVM使用ISO8859-1對中文進行編碼,當然就認不到了,于是那一個個的問號就來了。
??? 那怎么辦呢?既然捷徑走不通,我們就只好使用OutputSteamWriter 和 InputStreamReader了。
public void write() throws IOException{
? OutputStreamWriter osw = new OutputStreamWriter(
?????????????????????? new? FileOutputStream("test.txt"), "utf-8");
? osw.write("中國萬歲");
? osw.close();
}
public String read() throws IOException{
? InputStreamReader isr = new InputStreamReader(
??????? new FileInputStream("test.txt"),"utf-8");
? BufferedReader br = new BufferedReader(isr);
? String str = br.readLine();
? br.close();
? isr.close();
? return str;
}
??
???? 在這里,我們指定文件讀寫的編碼方式為utf-8,當然對于中文來說GBK和GB2312也是可以的,但是推薦使用UTF-8,這樣對于軟件的國際化很有好處。其實,這里指定編碼方式進行文件的寫入跟我們使用記事本等編輯器的另存為,并且指定格式為“UTF-8”在本質上是一樣的。通過上述處理后,程序就可以跨平臺運行了。
??? 在處理文件的過程中,我們還會用到RandomAccessFile這個類來隨機訪問文件。這里,如果我們寫入字符串的時候調用writeChars,那么,如果寫入的是中文,中文問題就又會出現(xiàn)了。因為此時RandomAccessFile并沒有使用系統(tǒng)的默認編碼來寫入文件,而是直接將內存中的二進制數據直接寫到文件中去。如何解決這個問題呢?只要讀寫對稱就行了。
public void randWrite() throws IOException{
? RandomAccessFile raf = new RandomAccessFile("test1.txt","rw");
? raf.writeChars("中國你好");
? raf.close();
}
public String randRead() throws IOException{
? RandomAccessFile raf = new RandomAccessFile("test1.txt","r");
? StringBuffer sb = new StringBuffer();
? while( raf.getFilePointer() < raf.length()){
?? sb.append( raf.readChar() );
? }
?? raf.close();
? return sb.toString();
}??
但是這樣處理起來不是很方便,我們可以這樣寫:
public void randWrite() throws IOException{
? RandomAccessFile raf = new RandomAccessFile("test1.txt","rw");
? raf.writeUTF("中國你好");
? raf.close();
}
public String randRead() throws Exception{
? RandomAccessFile raf = new RandomAccessFile("test1.txt","r");
? String str = raf.readUTF();
? raf.close();
? return str;
}
??
?? 好了,文件讀寫的中文問題就解決了。
文章來源:
http://x-spirit.spaces.live.com/Blog/cns!CC0B04AE126337C0!405.entry