似乎Files.newBufferedReader()
对UTF-8比对天真的替代方案更严格。
如果我创建一个单字节128的文件---所以,不是一个有效的UTF-8字符 - 如果我在BufferedReader
上构建一个InputStreamReader
,我将很高兴地阅读它<{1}}的结果,但Files.newInputStream()
会抛出异常。
此代码
Files.newBufferedReader()
有这个结果:
try (
InputStream in = Files.newInputStream(path);
Reader isReader = new InputStreamReader(in, "UTF-8");
Reader reader = new BufferedReader(isReader);
) {
System.out.println((char) reader.read());
}
try (
Reader reader = Files.newBufferedReader(path);
) {
System.out.println((char) reader.read());
}
这是否有记录?是否有可能通过�
Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(CoderResult.java:281)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.read(BufferedReader.java:182)
at TestUtf8.main(TestUtf8.java:28)
获得宽松的行为?
答案 0 :(得分:10)
区别在于如何在两种情况下构造用于解码UTF-8的CharsetDecoder
。
对于new InputStreamReader(in, "UTF-8")
,解码器使用:
Charset cs = Charset.forName("UTF-8");
CharsetDecoder decoder = cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
这明确指出无效序列只是用标准替换字符替换。
Files.newBufferedReader(path)
使用:
Charset cs = StandardCharsets.UTF_8;
CharsetDecoder decoder = cs.newDecoder();
在这种情况下,onMalformedInput
和onUnmappableCharacter
未被调用,因此您将获得默认操作,即抛出您看到的异常。
似乎没有办法改变Files.newBufferedReader
的作用。在查看代码时,我没有看到任何记录此内容的内容。
答案 1 :(得分:5)
据我所知,它没有在任何地方记录,并且不可能使newBufferedReader行为宽松。
但应该记录在案。实际上,在我看来,缺少有关它的文档是一个有效的Java错误,即使修改后的文档最终说“无效的字符集序列会导致未定义的行为。”
此外,由于没有关于这个问题的文件,我认为你不能安全地依赖你所观察到的行为。未来版本的InputStreamReader完全有可能默认使用严格的内部CharsetDecoder。
因此,为了保证宽松的行为,我会让你的代码更进一步:
try (
InputStream in = Files.newInputStream(path);
CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
decoder.onMalformedInput(CodingErrorAction.REPLACE);
Reader isReader = new InputStreamReader(in, decoder);
Reader reader = new BufferedReader(isReader);
) {
System.out.println((char) reader.read());
}