zoukankan      html  css  js  c++  java
  • IO数据流与转码


                                          


    from:http://www.oreilly.com.tw/sleepless/java_big5_2.htm
     
    I/O 轉碼
    Java 現行的 IO 一律使用 Stream 的方式,相關的類別都放在 java.io 中。輸出 binary 的資料使用 OutputStream 的子類別,輸入 binary 的資料使用 InputStream 的子類別,輸出文字的資料使用 Writer 的子類別,輸入文字的資料使用 Reader 的子類別。

    你可能會覺得很奇怪:「有必要用不同的方式來處理文字和 binary 嗎?文字資料不也是 binary 的一種?」沒錯,其實他們非常類似,最大的差異在於,InputStream/OutputStream 會原封不動地傳送資料,但是 Reader/Writer 會將資料當作文字對待,所以 Reader/Writer 在「必要時」會把(文字)資料轉碼。什麼時候才是所謂的「必要時」呢?

    Java 的 Stream(包括 Reader 和 Writer)是可以互相串接的。當 Reader 的資料來源是另一個 Reader 時,不轉碼,當 Reader 的資料來源是一個 InputStream 時,就會轉碼。當 Writer 的資料去處是另一個 Writer 時,不轉碼,當 Writer 的資料去處是一個 OutputStream 時,就會轉碼。

    由什麼碼轉成什麼碼?這是可以指定的。因為轉碼只發生在 Reader/InputStream 的交界處與 Writer/OutputStream 的交界處,所以正是由 InputStreamReader 和 OutputStreamWriter 此二類別負責,下面兩個 constructor 的第二個參數,正是用來指定轉碼的方式。

    public InputStreamReader(InputStream in, String enc)
             throws UnsupportedEncodingException;
    public OutputStreamWriter(OutputStream out, String enc)
             throws UnsupportedEncodingException;

    InputStreamReader 負責將 enc 的編碼方式轉成 Unicode(因為資料是從「外部」送過來給「內部」的),OutputStreamWriter 負責將 Unicode 的編碼方式轉成 enc(因為資料要從「內部」送給「外部」)。JRE 內部當然都一定是用 Unicode 編碼,而外部的編碼就不一定,要看當時的環境為何。你可以透過 getEncoding() 的 method,來得知 InputStreamReader 與 OutputStreamWriter 的編碼方式。

    請注意:即使你沒用到 InputStreamReader 與 OutputStreamWriter,只有用到其它的 Reader 和 Writer,但是這些 Reader 和 Writer 內部也很有可能(但非絕對)是直接或間接通到 InputStreamReader 與 OutputStreamWriter。比方說:FileReader 內部其實是透過一個 InputStreamReader 的仲介來將資料從 FileInputStream 取過來的,此時 InputStreamReader 的轉碼方式是採用 OS 的文字編碼(以繁體中文的 Windows 為例,就是「MS950」)轉成 Unicode。

    如果你清楚地知道你要讀寫的檔案(或資料來源 / 去處)是採用某種編碼方式,你也可以主動指定編碼方式。但是,請記得抓取可能導致的 UnsupportedEncodingException,並務必處理之,不可對此例外置之不理,因為該 JRE 有可能沒有附上此種編碼表(也有可能你的編碼名稱給錯)。

    檔案 I/O 轉碼
    如果你是在泰文版的 Windows 上,想讀取用 MS950 編碼的繁體中文文字檔,你就必須主動指定編碼,不可以直接用 FileReader,否則無法成功讀取。方法如下:

    FileInputStream fis = new FileInputStream(fileName);
    InputStreamReader reader = new InputStreamReader(fis, "MS950");

    然後,透過 Reader 讀出來的就會是正確的中文。

    網路 I/O 轉碼
    如果你的網路程式採用 TCP,那麼你可以透過 Socket 類別所提供的 getInputStream() 和 getOutputStream() 來得到 InputStream 和 OutputStream 物件。如果你是在泰文版的 Windows 上,想讀取用 MS950 編碼的繁體中文文字 TCP 網路串流,你可以用類似上面的技巧來轉碼。方法如下:

    InputStream is = mySocket.getInputStream();
    InputStreamReader reader = new InputStreamReader(is, "MS950");

    如果你的網路程式採用 UDP,你必須把中文字串轉成(或轉自)byte 陣列。請看下一節「 字串和 byte 陣列的轉碼 」。

    如果你的網路程式採用 RMI,那你完全不用為這部分的轉碼操心,字串直接用 Unicode 在網路上傳遞給另一個 JRE,不需要轉碼。

    保持刑案現場
    如果你不知道你的 I/O 資料來源或去處是用何種編碼方式,那麼你最好不要用 Reader 和 Writer,而應該直接用 InputStream 和 OutputStream,因為與其被 Reader 和 Writer 胡亂編碼之後造成資訊遺失或錯亂,不如保持資料的完整不變,留待以後進一步解讀。

    字串和 byte 陣列的轉碼
    java.lang.String 類別是 Java 字串物件的類別,Java 字串物件既然是活在 JRE 內部,當然就一定是用 Unicode 編碼。如果你需要將 String 物件和 byte 陣列互轉,你可以使用:

    String(byte[] bytes, int offset, int length, String enc);

              或

    String(byte[] bytes, String enc);

    來將用 enc 編碼的 byte 陣列,轉成 Unicode 的 String 物件。你也可以使用 String 物件所提供的:

    byte[] getBytes(String enc)

    來將 String 物件轉成 byte 陣列。

    另外,你也可以透過 ByteArrayInputStream 或 ByteArrayOutputStream 串接到 InputStreamReader 或 OutputStreamWriter,來達到轉碼的目的。

    http://macrochen.blogdriver.com/macrochen/414524.html


  • 相关阅读:
    Codechef EDGEST 树套树 树状数组 线段树 LCA 卡常
    BZOJ4319 cerc2008 Suffix reconstruction 字符串 SA
    Codechef STMINCUT S-T Mincut (CodeChef May Challenge 2018) kruskal
    Codeforces 316G3 Good Substrings 字符串 SAM
    Codechef CHSIGN Change the Signs(May Challenge 2018) 动态规划
    BZOJ1396 识别子串 字符串 SAM 线段树
    CodeForces 516C Drazil and Park 线段树
    CodeForces 516B Drazil and Tiles 其他
    CodeForces 516A Drazil and Factorial 动态规划
    SPOJ LCS2
  • 原文地址:https://www.cnblogs.com/bluespot/p/885780.html
Copyright © 2011-2022 走看看