Files.readAllBytes 与 Files.lines 获取 MalformedInputException
Files.readAllBytes vs Files.lines getting 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<String> 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.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.hasNext(BufferedReader.java:571)
... 4 more
这里有什么区别,我该如何解决?
Files.lines
默认使用 UTF-8 encoding,而从字节实例化新字符串将使用默认系统编码。您的文件似乎不是 UTF-8 格式,这就是它失败的原因。
检查您的文件使用的编码,并将其作为第二个参数传递。
这与 character encoding 有关。计算机只处理数字。要存储文本,必须使用某种方案将文本中的字符与数字相互转换。该方案称为字符编码。有许多不同的字符编码;一些著名的标准字符编码是 ASCII、ISO-8859-1 和 UTF-8。
在第一个示例中,您读取了文件中的所有字节(数字),然后通过将它们传递给 class String
的构造函数将它们转换为字符。这将使用您系统的默认字符编码(无论它在您的操作系统上是什么)将字节转换为字符。
在第二个示例中,您使用 Files.lines(...)
,根据 the documentation,将使用 UTF-8 字符编码。当在文件中发现不是有效 UTF-8 序列的字节序列时,您将得到 MalformedInputException
.
您系统的默认字符编码可能是也可能不是 UTF-8,因此这可以解释行为上的差异。
您必须找出文件使用的字符编码,然后明确使用它。例如:
String content = new String(Files.readAllBytes(Paths.get("_template.txt")),
StandardCharsets.ISO_8859_1);
第二个例子:
Stream<String> lines = Files.lines(Paths.get("_template.txt"),
StandardCharsets.ISO_8859_1);
为了补充, what happens here (and is undocumented!) is that Files.lines()
creates a CharsetDecoder
whose policy is to reject invalid byte sequences; that is, its CodingErrorAction
设置为REPORT
。
这与 JDK 提供的几乎所有其他 Reader
实施不同,后者的标准政策是 REPLACE
。此策略将导致所有不可映射的字节序列发出 replacement character (U+FFFD).
2017年使用:
Charset.forName("ISO_8859_1") instead of Charsets.ISO_8859_1
我原以为以下两种读取文件的方法应该表现相同。但他们没有。第二种方法是抛出 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<String> 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.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.hasNext(BufferedReader.java:571)
... 4 more
这里有什么区别,我该如何解决?
Files.lines
默认使用 UTF-8 encoding,而从字节实例化新字符串将使用默认系统编码。您的文件似乎不是 UTF-8 格式,这就是它失败的原因。
检查您的文件使用的编码,并将其作为第二个参数传递。
这与 character encoding 有关。计算机只处理数字。要存储文本,必须使用某种方案将文本中的字符与数字相互转换。该方案称为字符编码。有许多不同的字符编码;一些著名的标准字符编码是 ASCII、ISO-8859-1 和 UTF-8。
在第一个示例中,您读取了文件中的所有字节(数字),然后通过将它们传递给 class String
的构造函数将它们转换为字符。这将使用您系统的默认字符编码(无论它在您的操作系统上是什么)将字节转换为字符。
在第二个示例中,您使用 Files.lines(...)
,根据 the documentation,将使用 UTF-8 字符编码。当在文件中发现不是有效 UTF-8 序列的字节序列时,您将得到 MalformedInputException
.
您系统的默认字符编码可能是也可能不是 UTF-8,因此这可以解释行为上的差异。
您必须找出文件使用的字符编码,然后明确使用它。例如:
String content = new String(Files.readAllBytes(Paths.get("_template.txt")),
StandardCharsets.ISO_8859_1);
第二个例子:
Stream<String> lines = Files.lines(Paths.get("_template.txt"),
StandardCharsets.ISO_8859_1);
为了补充Files.lines()
creates a CharsetDecoder
whose policy is to reject invalid byte sequences; that is, its CodingErrorAction
设置为REPORT
。
这与 JDK 提供的几乎所有其他 Reader
实施不同,后者的标准政策是 REPLACE
。此策略将导致所有不可映射的字节序列发出 replacement character (U+FFFD).
2017年使用:
Charset.forName("ISO_8859_1") instead of Charsets.ISO_8859_1