使用Files.newBufferedReader()读取文件并直接构建读者的结果不同

RTS*_*lio 8 java file utf-8 java-8 nio2

似乎Files.newBufferedReader()对UTF-8比对天真的替代品更严格.

如果我创建一个单字节128的文件---所以,不是一个有效的UTF-8字符---如果我在结果上构造一个BufferedReaderon ,但是抛出异常会很高兴.InputStreamReaderFiles.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());
}
Run Code Online (Sandbox Code Playgroud)

有这个结果:

?
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)
Run Code Online (Sandbox Code Playgroud)

这记录了吗?是否有可能获得宽松的行为Files.newBufferedReader()

gre*_*449 10

区别在于如何CharsetDecoder在两种情况下构造用于解码UTF-8的方法.

对于new InputStreamReader(in, "UTF-8")解码器使用以下构造:

Charset cs = Charset.forName("UTF-8");

CharsetDecoder decoder = cs.newDecoder()
          .onMalformedInput(CodingErrorAction.REPLACE)
          .onUnmappableCharacter(CodingErrorAction.REPLACE);
Run Code Online (Sandbox Code Playgroud)

这明确指出无效序列只是替换为标准替换字符.

Files.newBufferedReader(path) 用途:

Charset cs = StandardCharsets.UTF_8;

CharsetDecoder decoder = cs.newDecoder();
Run Code Online (Sandbox Code Playgroud)

在这种情况下onMalformedInput,onUnmappableCharacter并且没有被调用,因此您将获得默认操作,即抛出您看到的异常.

似乎没有办法改变做什么Files.newBufferedReader.在查看代码时,我没有看到任何记录此内容的内容.


VGR*_*VGR 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());
}
Run Code Online (Sandbox Code Playgroud)