为什么美国标准ASCII编码接受非美国标准ASCII字符?

3

Consider the following code:

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

为什么使用 US-ASCII 的第二个 readAndPrint() 调用成功了呢?我本以为它会报错,因为输入不是这种编码中的合适字符。Java API 或 JLS 中指定了这种行为的地方在哪里?

2个回答

9
在输入流中发现无法解码的字节时,默认操作是用 Unicode 字符U+FFFD 替换字符来代替它们。
如果您想要更改这个操作,可以将一个CharacterDecoder传递给InputStreamReader,该对象配置了不同的CodingErrorAction
CharsetDecoder decoder = Charset.forName(usingEncoding).newDecoder();
decoder.onMalformedInput(CodingErrorAction.REPORT);
InputStreamReader isr = new InputStreamReader(bais, decoder);

谢谢你的回答。问题是我无法轻松更改创建InputStreamReader的代码,因为它不是我的 - org.apache.tools.ant.taskdefs.SQLExec.Transaction.runTransaction(PrintStream)。我很惊讶地发现Ant的<sql>任务的encoding属性不能防止输入格式不正确。 - Grzegorz Oledzki
@Grzegorz:我认为这是一个错误。至少当指定了“encoding”时,任务应该强制执行编码,包括报告错误。如果未指定,则可能更好地容忍错误。也许添加一个“strictEncoding”属性或类似的东西会更合适。 - Joachim Sauer
我已经在Ant的错误数据库中提交了一个问题:https://issues.apache.org/bugzilla/show_bug.cgi?id=50715,但我不希望这个问题很快得到解决。 - Grzegorz Oledzki

3

我认为,这与构造函数String(byte bytes[], int offset, int length, Charset charset)的情况相同:

此方法始终使用此字符集的默认替换字符串替换格式不正确的输入和无法映射的字符序列。当需要对解码过程进行更多控制时,应使用java.nio.charset.CharsetDecoder类。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接