2011-02-03 226 views
3

考慮下面的代碼:爲什麼US-ASCII編碼接受非US-ASCII字符?

public class ReadingTest { 

    public void readAndPrint(String usingEncoding) throws Exception { 
     ByteArrayInputStream bais = new ByteArrayInputStream(new byte[]{(byte) 0xC2, (byte) 0xB5}); // 'micro' sign UTF-8 representation 
     InputStreamReader isr = new InputStreamReader(bais, usingEncoding); 
     char[] cbuf = new char[2]; 
     isr.read(cbuf); 
     System.out.println(cbuf[0]+" "+(int) cbuf[0]); 
    } 

    public static void main(String[] argv) throws Exception { 
     ReadingTest w = new ReadingTest(); 
     w.readAndPrint("UTF-8"); 
     w.readAndPrint("US-ASCII"); 
    } 
} 

觀察輸出:

µ 181 
? 65533 

爲什麼的readAndPrint()(使用US-ASCII的一個)的第二個呼叫成功嗎?我期望它會拋出一個錯誤,因爲在這種編碼中輸入不是合適的字符。 Java API或JLS中要求這種行爲的地方是什麼?

回答

9

在輸入流中發現不可解碼字節時的默認操作是用Unicode字符U+FFFD REPLACEMENT CHARACTER替換它們。

如果你想改變這種狀況,你可以通過一個CharacterDecoderto the InputStreamReader它配置了不同的CodingErrorAction

CharsetDecoder decoder = Charset.forName(usingEncoding).newDecoder(); 
decoder.onMalformedInput(CodingErrorAction.REPORT); 
InputStreamReader isr = new InputStreamReader(bais, decoder); 
+0

感謝您的回答。問題是我無法輕易更改創建`InputStreamReader`的代碼,因爲它不是我的``org.apache.tools.ant.taskdefs.SQLExec.Transaction.runTransaction(PrintStream)`。我很驚訝地發現Ant的``任務的encoding屬性並不能防止錯誤的輸入。 – 2011-02-03 14:06:52

3

我會說,這是相同的構造 String(byte bytes[], int offset, int length, Charset charset)

此方法始終用此字符集的默認替換字符串替換格式錯誤的輸入和不可映射字符序列。當需要對解碼過程進行更多的控制時,應該使用java.nio.charset.CharsetDecoder類。

使用CharsetDecoder您可以指定不同的CodingErrorAction

相關問題