【问题标题】:Can UTF8 validation be done on a char[], or must it be done at the original byte[]?UTF8 验证可以在 char[] 上完成,还是必须在原始 byte[] 上完成?
【发布时间】:2021-09-23 15:26:48
【问题描述】:

我正在尝试验证我正在摄取的文件是否都严格符合 UTF8,并且通过我的几次阅读,我得出的结论是,如果要正确完成验证,数据的原始、未篡改字节必须进行分析。如果在事后尝试查看字符串本身,他们不太可能发现是否有任何字符不兼容 UTF8,因为 Java 会尝试转换它们。

我正在正常读取文件:我从文件中收到InputStream,然后将InputStreamReader 提供给它,然后将其提供给BufferedReader。它看起来像:

InputStream is = new FileInputStream(fileLocation);
InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8)));
BufferedReader br = new BufferedReader(isr);

我可以重写 BufferedReader 类,为它偶然发现的每个字符添加一些验证。

问题是BufferedReader 有一个char[],而不是byte[],用于缓冲区。这意味着字节会自动转换为字符。

所以,我的问题是:这个验证可以在 BufferedReader 中的char[] 级别完成吗?虽然我在这里有点“强制”UTF8:

InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8)));

我看到字符从非 utf-8(比如 utf-16)转换为 utf-8,并破坏了一些系统。我不知道 char[] 对于此验证而言基本上“为时已晚”。是吗?

【问题讨论】:

  • "可以在位于BufferedReaderchar[] 级别完成此验证吗?" - 否。到那时,UTF-8 已经被解析并解码为char[]。如果出现问题,char[] 将不会包含正确的字符。所以,你真的需要验证原来的byte[]
  • @RemyLebeau 感谢您的回复!
  • 嘿@RemyLebeau,我有一个问题。如果一个文件包含 UTF16 编码的字形,并且我将 BufferedReader 设置为使用 UTF8,我不会收到错误消息,并且当我调用 readLine() 时,该值会以字符串的形式正常返回。这里发生了什么?
  • 我假设您的意思是 InputStreamReader 而不是 BufferedReaderBufferedReader 将存储并返回 InputStreamReader 分配的字符集从将字节解码为字符输出的任何 UTF-16 代码单元。如果编码不匹配,可能会返回错误的字符,甚至会被省略。默认情况下,解码将返回'\uFFFD' 字符以表示解码错误。如果您想更改该行为,请使用 CharsetDecoder 创建 InputStreamReader,其 malformedInputunmappableCharacter 操作已根据需要进行自定义。

标签: java utf-8 inputstream bufferedreader inputstreamreader


【解决方案1】:

定义 UTF-8 兼容。有 2 个事件可以合理地称为“无效”。 UTF-8 作为一种格式将 32 位数字转换为字节序列,不能只转换任何数字,只能转换有限的集合(但所有可能出现在 unicode 中的数字都可以转换)。

  • 对不存在的字形进行有效转换。

并非 UTF-8 可以存储的每一个 32 位数字实际上都是有效的 unicode 代码点。但是,unicode 一直在扩展。今天无效的东西明天可能有效。除非您加载了整个 unicode 表,否则无法真正了解这些内容。

  • 无效序列

通常在将字节转换为文本(char、String、Reader、Writer、StringBuilder - 任何面向字符的内容)时,如果您尝试转换无效的字节序列,您会得到一个异常或者进程处于宽松模式, 失败被转换成一个字符,意思是“这不是有效的”。

如果发生异常,那么您不可能有一个 char 数组(发生了异常而不是返回一个 char 数组)。如果没有,您的字符中就有该字形,所以只需搜索即可。

【讨论】:

  • 这些是一些实实在在的观点。我很感激。我想我最感兴趣的是“对不存在的字形进行有效转换”的场景。我同意你的观点;我必须加载整个 unicode 表。我想这需要更多的努力而不是值得的。感谢您的洞察力。
  • 当然,给你最大控制权的课程是java.nio.charset.CharsetDecoder
猜你喜欢
  • 1970-01-01
  • 2021-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多