java - 查询从 "UTF-8"world读取字节到Java "char"

标签 java character-encoding nio bytebuffer

使用此 link 中给出的以下代码片段,

byte[] bytes = {0x00, 0x48, 0x00, 0x69, 0x00, 0x2C,
                      0x60, (byte)0xA8, 0x59, 0x7D, 0x00, 0x21};  // "Hi,您好!"

Charset charset = Charset.forName("UTF-8");
// Encode from UCS-2 to UTF-8
// Create a ByteBuffer by wrapping a byte array
ByteBuffer bb = ByteBuffer.wrap(bytes);
// Create a CharBuffer from a view of this ByteBuffer
CharBuffer cb = bb.asCharBuffer();

使用wrap()方法,“新缓冲区将由给定的字节数组支持”,这里我们没有任何从字节到其他格式的编码,它只是将字节数组放在一个缓冲区。

请你帮我理解一下,当我们在上面的代码中说bb.asCharBuffer()时,我们到底在做什么?cb类似于字符数组。因为 char 在 Java 中是 UTF-16,使用 asCharBuffer() 方法,我们是否将 bb 中的每 2bytes 视为 char?这是正确的方法吗?如果不是,请帮助我采取正确的方法。

编辑: 我尝试了下面 Meisch 推荐的这个程序,

byte[] bytes = {0x00, 0x48, 0x00, 0x69, 0x00, 0x2C,
                0x60, (byte)0xA8, 0x59, 0x7D, 0x00, 0x21};  // "Hi,您好!"

        Charset charset = Charset.forName("UTF-8");
        CharsetDecoder decoder = charset.newDecoder();
        ByteBuffer bb = ByteBuffer.wrap(bytes);
        CharBuffer cb = decoder.decode(bb);

给出异常

Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 1
    at java.nio.charset.CoderResult.throwException(Unknown Source)
    at java.nio.charset.CharsetDecoder.decode(Unknown Source)
    at TestCharSet.main(TestCharSet.java:16)

请帮帮我,我卡在这里!!!

注意:我使用的是 java 1.6

最佳答案

你问:“因为 char 在 Java 中是 UTF-16,使用 asCharBuffer() 方法,我们是否考虑 bb 中的每 2 个字节> 作为 char?”

这个问题的答案是肯定的。你的理解是正确的。

您的下一个问题是:“这是正确的方法吗?”

如果您只是想演示 ByteBuffer、CharBuffer 和 Charset 类的工作原理,这是可以接受的。

但是,当您编写应用程序时,您永远不会编写那样的代码。首先,不需要字节数组;您可以将字符表示为文字字符串:

String s = "Hi,\u60a8\u597d!";

如果你想将字符串转换为UTF-8字节,你可以简单地这样做:

byte[] encodedBytes = s.getBytes(StandardCharsets.UTF_8);

如果您仍在使用 Java 6,您可以改为这样做:

byte[] encodedBytes = s.getBytes("UTF-8");

更新:您的字节数组代表 UTF-16BE(大端)编码中的字符。具体来说,您的数组每个字符正好有两个字节。这不是有效的 UTF-8 编码字节序列,这就是您收到 MalformedInputException 的原因。

当字符编码为UTF-8字节时,每个字符将用1到4个字节表示。要使您的第二个代码片段正常工作,数组必须是:

byte[] bytes = {
    0x48, 0x69, 0x2c,                       // ASCII chars are 1 byte each
    (byte) 0xe6, (byte) 0x82, (byte) 0xa8,  // U+60A8
    (byte) 0xe5, (byte) 0xa5, (byte) 0xbd,  // U+597D
    0x21
};

当从字节转换为字符时,我之前的声明仍然适用:您不需要 ByteBuffer 或 CharBuffer 或 Charset 或 CharsetDecoder。您可以使用这些类,但通常只创建一个字符串更简洁:

String s = new String(bytes, "UTF-8");

如果你想要一个 CharBuffer,只需包装字符串:

CharBuffer cb = CharBuffer.wrap(s);

您可能想知道何时适合直接使用 CharsetDecoder。如果字节来自不受您控制的源,并且您有充分的理由相信它可能不包含正确的 UTF-8 编码字节,您就会这样做。使用显式 CharsetDecoder 允许您自定义如何处理无效字节。

关于java - 查询从 "UTF-8"world读取字节到Java "char",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27692989/

相关文章:

php - 如何删除字符

character-encoding - 如何解码乱码编码: Special Character Encoding

java 网络,写入调用平均比读取调用长 4 倍,这正常吗?

java - 参数中的类函数

Java 比较数组和ArrayList

java - Greenfoot 计数器减一

java - Google App Engine 的响应编码(不能改变响应编码)

java - 在Java中读取xml文件 - 仅选定的元素

java - 使用 java nio 将字符串写入文件的最佳方法

从 Google Cloud Storage 下载时的 Java NIO 阻塞/非阻塞问题