如何在Java中将CharSequence转换为UTF-8编码的字节数组?

zdwk9cvp  于 2023-05-15  发布在  Java
关注(0)|答案(1)|浏览(298)

我正在尝试将CharSequence转换为UTF-8编码的byte[]数组。
我一直有问题,所以我想问stackoverflow的帮助。我想写一个 Java Fiddle 来实现它:
https://www.mycompiler.io/view/3MliN0HgwDD
只是小提琴本身不管用:

import java.util.*;
import java.lang.*;
import java.io.*;
import java.nio.*;
import java.nio.charset;

// The main method must be in a class named "Main".
class Main {
    public static byte[] charSequenceToUtf8(final CharSequence input)
    {
        //char[] chars = new char[input.length];
        //for (int i=0; i<input.length; i++)
        //  chars[i] = input.charAt(i);

        CharBuffer charBuffer = CharBuffer.wrap(input);
        checkEquals(10, charBuffer.length(), "Charbuffer is wrong length");

        Charset cs = Charset.forName("UTF-8"); 
        ByteBuffer byteBuffer = cs.encode(charBuffer);
        checkEquals(10, byteBuffer.length(), "byteBuffer is wrong length");
        
        byte[] utf8 = byteBuffer.array();        
        checkEquals(10, utf8.length, "utf8 bytes is wrong length");
    }
    
    public static void checkEquals(int expected, int actual, String message)
    {
        if (expected == actual)
            return;
            
        String sExpected = String.valueOf(expected);
        String sActual = String.valueOf(actual);
        
        throw new Exception("Test failed. Expected "+sExpected+", Actual "+sActual+". "+message);
    }
    
    public static void main(String[] args) {
        test("AAAAAAAAAA"); //ten A's
    }
}

java.nio至少需要Java 7 ref。这就是为什么它在Java 16中不工作的原因:

所以这带来了很多问题:

  • 如何将CharSequence数组转换为byte[]数组?1
  • 为什么在Java 16中不能使用?

最后,实际的错误是,尝试编码字符串AAAAAAAAA返回一个11元素的数组:
| 字符序列|UTF-8字节数组|
| --------------|--------------|
| * AA | [65, 65]|
| “AAA”|[65, 65, 65]|
| “AAAA”
| [65, 65, 65, 65]|
| “AAAAA”| [65, 65, 65, 65, 65]|
| * “AAAAAA”
| [65, 65, 65, 65, 65, 65]|
| * “啊啊啊”| [65, 65, 65, 65, 65, 65, 65]|
| * “啊啊啊啊”
| [65, 65, 65, 65, 65, 65, 65, 65]|
| * “啊啊啊啊啊”| [65, 65, 65, 65, 65, 65, 65, 65, 65]|
| * “啊啊啊啊啊啊”
| [65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 0]|
为什么上面的代码,我从链接的问题中偷来的,失败的是一个10个字符的字符串?

wj8zmpe1

wj8zmpe11#

首先,请注意,如果你有一个String,那么你可以简单地这样做:

byte[] bytes = theString.getBytes(StandardCharsets.UTF_8);

或者,即使你有一个CharSequence,你也可以这样做:

byte[] bytes = theCharSequence.toString().getBytes(StandardCharsets.UTF_8);

这可能会创建CharSequenceString * 副本 *,如果它还不是String的话,尽管它应该很快被垃圾收集。
但是关于你的问题,你没有考虑ByteBuffer的限制(或位置,尽管在这种情况下是0)。无论出于何种原因,对"AAAAAAAAAA"进行编码会导致缓冲区的容量11,但其限制10。但是#array()方法返回整个后台数组,而不管缓冲区的位置或限制。这意味着在将ByteBuffer转换为byte[]时,您需要手动考虑限制(和位置)。
例如:

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class Main {

  public static void main(String[] args) throws Exception {
    for (int i = 1; i <= 10; i++) {
      String string = "A".repeat(i);

      CharBuffer chars = CharBuffer.wrap(string);
      ByteBuffer bytes = StandardCharsets.UTF_8.encode(chars);

      System.out.printf("%-10s | %s%n", string, Arrays.toString(toByteArray(bytes)));
    }
  }

  public static byte[] toByteArray(ByteBuffer buffer) {
    byte[] array = new byte[buffer.remaining()];
    buffer.get(buffer.position(), array);
    return array;
  }
}

它将输出:

A          | [65]
AA         | [65, 65]
AAA        | [65, 65, 65]
AAAA       | [65, 65, 65, 65]
AAAAA      | [65, 65, 65, 65, 65]
AAAAAA     | [65, 65, 65, 65, 65, 65]
AAAAAAA    | [65, 65, 65, 65, 65, 65, 65]
AAAAAAAA   | [65, 65, 65, 65, 65, 65, 65, 65]
AAAAAAAAA  | [65, 65, 65, 65, 65, 65, 65, 65, 65]
AAAAAAAAAA | [65, 65, 65, 65, 65, 65, 65, 65, 65, 65]

请注意,上面的示例复制了缓冲区的后备数组的一个区域,尽管原始的ByteBuffer应该很快被垃圾收集。我能想到的避免复制后台数组的唯一方法是修改代码以直接使用ByteBuffer(如果只返回后台数组,则会丢失位置/限制信息)。或者我想你可以创建一个 Package 器类。

相关问题