Files.readAllBytes vs Files.lines获取MalformedInputException

我原以为以下两种读取文件的方法应该是一样的。 但他们没有。 第二种方法是抛出MalformedInputException

 public static void main(String[] args) { try { String content = new String(Files.readAllBytes(Paths.get("_template.txt"))); System.out.println(content); } catch (IOException e) { e.printStackTrace(); } try(Stream lines = Files.lines(Paths.get("_template.txt"))) { lines.forEach(System.out::println); } catch (IOException e) { e.printStackTrace(); } } 

这是堆栈跟踪:

 Exception in thread "main" java.io.UncheckedIOException: java.nio.charset.MalformedInputException: Input length = 1 at java.io.BufferedReader$1.hasNext(BufferedReader.java:574) at java.util.Iterator.forEachRemaining(Iterator.java:115) at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580) at Test.main(Test.java:19) Caused by: 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.readLine(BufferedReader.java:324) at java.io.BufferedReader.readLine(BufferedReader.java:389) at java.io.BufferedReader$1.hasNext(BufferedReader.java:571) ... 4 more 

这有什么区别,我该如何解决?

这与字符编码有关 。 计算机只处理数字。 要存储文本,必须使用某种方案将文本中的字符转换为数字或从数字转换。 该方案称为字符编码。 有许多不同的字符编码; 一些众所周知的标准字符编码是ASCII,ISO-8859-1和UTF-8。

在第一个示例中,您读取文件中的所有字节(数字),然后通过将它们传递给String类的构造函数将它们转换为字符。 这将使用系统的默认字符编码(无论在您的操作系统上是什么)将字节转换为字符。

在第二个示例中,使用Files.lines(...) ,将使用UTF-8字符编码,根据文档 。 当在文件中找到不是有效UTF-8序列的字节序列时,您将收到MalformedInputException

系统的默认字符编码可能是也可能不是UTF-8,因此可以解释行为的差异。

您必须找出文件使用的字符编码,然后明确地使用它。 例如:

 String content = new String(Files.readAllBytes(Paths.get("_template.txt")), StandardCharsets.ISO_8859_1); 

第二个例子:

 Stream lines = Files.lines(Paths.get("_template.txt"), StandardCharsets.ISO_8859_1); 

为了补充Jesper的答案 ,这里发生的事情(并且没有Files.lines() !)是Files.lines()创建一个CharsetDecoder其策略是拒绝无效的字节序列; 也就是说,它的CodingErrorAction设置为REPORT

这与JDK提供的几乎所有其他Reader实现不同,后者的标准策略是REPLACE 。 此策略将导致所有不可映射的字节序列发出替换字符(U + FFFD) 。

默认情况下, Files.lines使用UTF-8编码 ,而从字节实例化新的String将使用默认的系统编码。 您的文件似乎不是UTF-8,这就是它失败的原因。

检查文件使用的编码,并将其作为第二个参数传递。

2017使用:

  Charset.forName("ISO_8859_1") instead of Charsets.ISO_8859_1