gpt4 book ai didi

java - 读取格式错误的文件时 StreamDecoder 与 InputStreamReader

转载 作者:行者123 更新时间:2023-11-30 02:26:50 24 4
gpt4 key购买 nike

我在 Java 8 中读取文件时遇到了一些奇怪的行为,我想知道是否有人能理解它。

场景:

读取格式错误的文本文件。我所说的格式错误是指它包含不映射到任何 unicode 代码点的字节。

我用来创建此类文件的代码如下:

byte[] text = new byte[1];
char k = (char) -60;
text[0] = (byte) k;
FileUtils.writeByteArrayToFile(new File("/tmp/malformed.log"), text);

此代码生成一个仅包含一个字节的文件,该文件不是 ASCII 表(也不是扩展表)的一部分。

尝试 cat 此文件会产生以下输出:


这是UNICODE Replacement Character 。这是有道理的,因为 UTF-8 需要 2 个字节才能解码非 ascii 字符,但我们只有一个字节。这也是我期望 Java 代码出现的行为。

贴一些常用代码:

private void read(Reader reader) throws IOException {

CharBuffer buffer = CharBuffer.allocate(8910);

buffer.flip();

// move existing data to the front of the buffer
buffer.compact();

// pull in as much data as we can from the socket
int charsRead = reader.read(buffer);

// flip so the data can be consumed
buffer.flip();

ByteBuffer encode = Charset.forName("UTF-8").encode(buffer);
byte[] body = new byte[encode.remaining()];
encode.get(body);

System.out.println(new String(body));
}

这是我使用 nio 的第一种方法:

FileInputStream inputStream = new FileInputStream(new File("/tmp/malformed.log"));
read(Channels.newReader(inputStream.getChannel(), "UTF-8");

这会产生以下异常:

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.Reader.read(Reader.java:100)

这不是我所期望的,但也有一定道理,因为这实际上是一个损坏的非法文件,并且异常基本上告诉我们它期望读取更多字节。

我的第二个(使用常规的java.io):

FileInputStream inputStream = new FileInputStream(new File("/tmp/malformed.log"));
read(new InputStreamReader(inputStream, "UTF-8"));

这不会失败,并产生与 cat 完全相同的输出:


这也是有道理的。

所以我的问题是:

  1. 在此场景中 Java 应用程序的预期行为是什么?
  2. 为什么使用 Channels.newReader(返回 StreamDecoder)和简单使用常规 InputStreamReader 之间存在差异?我的阅读方式有问题吗?

如有任何澄清,我们将不胜感激。

谢谢:)

最佳答案

行为之间的差异实际上可以追溯到 StreamDecoder and Charset classesInputStreamReaderStreamDecoder.forInputStreamReader(..) 获取 CharsetDecoder,它会在错误时进行替换

StreamDecoder(InputStream in, Object lock, Charset cs) {
this(in, lock,
cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE));
}

Channels.newReader(..) 使用默认设置创建解码器(即报告而不是替换,这会导致进一步的异常)

public static Reader newReader(ReadableByteChannel ch,
String csName) {
checkNotNull(csName, "csName");
return newReader(ch, Charset.forName(csName).newDecoder(), -1);
}

所以它们的工作方式不同,但文档中没有任何关于差异的指示。这是没有很好的记录的,但我假设他们改变了功能,因为你宁愿得到一个异常,也不愿让你的数据默默地损坏。

处理字符编码时要小心!

关于java - 读取格式错误的文件时 StreamDecoder 与 InputStreamReader,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45437358/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com