java - 将字符串编码为 UTF-8 字节时添加空字符?

标签 java character-encoding

代码片段:

public static void main(String[] args) {
    String s = "qwertyuiop";
    System.out.println(Arrays.toString(Charset
       .forName("UTF-8")
       .encode(s)
       .array()));
}

打印:

[113, 119, 101, 114, 116, 121, 117, 105, 111, 112, 0]

这似乎是因为,在幕后,对于 java.nio.charset.CharsetEncoder 类中的 UTF-8,averageBytesPerChar 变量似乎是 1.1。因此它分配了 11 个字节而不是 10 个字节,并且假设输入字符串只包含良好的旧单字节字符,我最后得到了那个奇怪的空字符。

我想知道这是否有任何记录?

本页:

https://docs.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html#encode(java.lang.String)

没有提供有关此类行为的线索。

P. S. 我是否理解正确,在任何情况下,上面的代码片段最好替换为:

s.getBytes(StandardCharsets.UTF_8)

正如我从其源代码中看到的那样,它还修剪了结果以避免那些空字符?

那么,java.nio.charset.Charset 的 encode(String s) 应该用来做什么?

最佳答案

问题不在Charset.encode(),而是在Buffer.array()

如果你打印Charset.forName("UTF-8").encode(s),你会发现输出是

java.nio.HeapByteBuffer[pos=0 lim=10 cap=11]

ByteBuffer 的限制为 10,即字符串的长度,容量 为 11,即缓冲区的总分配大小。如果您更改编码,限制和容量可能会有更大的变化,例如

System.out.println(Charset.forName("UTF-16").encode(s));
// java.nio.HeapByteBuffer[pos=0 lim=22 cap=41]
// (2 extra bytes because of the BOM, not null-termination)

当你call .array() ,它将返回整个后备数组,因此即使超出限制的内容也会被包括在内。

提取Java字节数组的实际方法是通过the .get() method :

ByteBuffer buf = Charset.forName("UTF-8").encode(s);
byte[] encoded = new byte[buf.limit()];
buf.get(encoded);
System.out.println(Arrays.toString(encoded));

这看起来很乱?因为“nio”的意思是Nativenative I/O。 Buffer 类型的创建使其可以轻松包装 C 数组。它使得与 native 代码的交互(例如读/写文件或发送/接收网络数据)变得非常高效。这些 NIO API 通常直接采用 Buffer,而不会在两者之间构造任何 byte[]。如果您只使用 Buffer,则中间两行不需要存在 :)。

如果整个操作都在 Java 中,是的,只需调用 s.getBytes(StandardCharsets.UTF_8)

关于java - 将字符串编码为 UTF-8 字节时添加空字符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42912994/

相关文章:

java - 自定义光标java

java - 在 Java 中将函数序列化为数据?

php - 令人困惑的mysql字符编码

php - 在数据库中存储数据时是否需要使用 HTML 实体?

java - Java 中不同步的 getter/setter 行为

java - Java源代码中的 ".class"到底是什么

java - 未找到文件异常 - 从 jar 执行时资源文件夹中的数据文件抛出异常

Git - 支持外来字符集

utf-8 - 数据 URI 中的字符集

java - Unicode码指向字节并反转: how do you do that in C++?