2011-02-03 218 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

相关问题