【问题标题】:Byte Array, when converted to string, then concatenated, returns equal String but unequal byte array字节数组,当转换为字符串,然后连接时,返回相等的字符串但不相等的字节数组
【发布时间】:2021-09-28 11:32:43
【问题描述】:

我有一个字节数组。我需要将带有分隔符的字符串连接到它。然后我想取回字节数组。在所有这些逻辑之后,输出字节数组不等于输入。在java中:

这在最后一行失败了:

    @Test
    void test1() {
        byte[] initialBytes = RandomUtils.nextBytes(64);
        String initialString = new String(initialBytes, StandardCharsets.UTF_8);

        String concatenatedString = String.join("\t", "Pre", initialString);
        byte[] concatenatedStringToBytes = concatenatedString.getBytes(StandardCharsets.UTF_8);

        String concatenatedBytesBackToString = new String(concatenatedStringToBytes, StandardCharsets.UTF_8);

        int indexOfDelimeter = concatenatedBytesBackToString.indexOf("\t");
        String finalString = concatenatedBytesBackToString.substring(indexOfDelimeter + 1);

        byte[] finalBytes = finalString.getBytes(StandardCharsets.UTF_8);

        assertEquals(initialString, finalString);
        assertTrue(Arrays.equals(initialBytes, finalBytes));
    }

【问题讨论】:

  • 两种可能。您的随机生成的字节不代表一个有效的String,或者它们代表一个String,它有多个可能的UTF-8 表示。
  • Arrays.equals(initialBytes, finalBytes) 是假的不是一个非常可能和有效的结果吗?
  • @sarveshseri - 是的,但是对应于这些字节数组的字符串是相等的。所以我很困惑为什么 byte[] 不相等。
  • 更改它以在两个字节数组不相等时转储它们并查看它们。

标签: java arrays string byte delimiter


【解决方案1】:

在 Java 中,String 值使用 UTF_16

由于UTF_16UTF_8 具有不同的字符覆盖范围,从UTF_8UTF_16 的转换可能会导致信息丢失(如果使用了那些不匹配的字符)。因此,当您转换回UTF_8 时,您将不会得到相同的字节数组。

public static void tryCharsetEncodingForRandomBytes() {
    byte[] initialBytes = getRandomBytes(64);
    String initialString = new String(initialBytes, StandardCharsets.UTF_8);

    byte[] finalBytes = initialString.getBytes(StandardCharsets.UTF_8);
    String finalString = new String(finalBytes, StandardCharsets.UTF_8);

    System.out.println(finalString.equals(initialString));
    System.out.println(initialBytes.length);
    System.out.println(finalBytes.length);
    System.out.println(Arrays.equals(initialBytes, finalBytes));
}

输出:

true
64
103
false

在处理更受欢迎的字符时,您不会遇到这种信息丢失的情况,例如 AlphaNumerics,它们在 UTF_16UTF_8 字符集中都很常见。

public static void tryCharsetEncodingForAlphanumeric() {
    String alphaNumeric = "abcd1234";

    byte[] initialBytes = alphaNumeric.getBytes(StandardCharsets.UTF_8);
    String initialString = new String(initialBytes, StandardCharsets.UTF_8);

    byte[] finalBytes = initialString.getBytes(StandardCharsets.UTF_8);
    String finalString = new String(finalBytes, StandardCharsets.UTF_8);

    System.out.println(finalString.equals(initialString));
    System.out.println(initialBytes.length);
    System.out.println(finalBytes.length);
    System.out.println(Arrays.equals(initialBytes, finalBytes));
}

输出:

true
8
8
true

这意味着只要您处理UTF_8UTF_16 中的常见字符,您的测试就会通过。

public static void yourTestScenarioWithAlphaNumeric() {
    String alphaNumeric = "abcdefghijklmop1234567890";

    byte[] initialBytes = alphaNumeric.getBytes(StandardCharsets.UTF_8);
    String initialString = new String(initialBytes, StandardCharsets.UTF_8);

    String concatenatedString = String.join("\t", "Pre", initialString);
    byte[] concatenatedStringToBytes = concatenatedString.getBytes(StandardCharsets.UTF_8);

    String concatenatedBytesBackToString = new String(concatenatedStringToBytes, StandardCharsets.UTF_8);

    int indexOfDelimiter = concatenatedBytesBackToString.indexOf("\t");
    String finalString = concatenatedBytesBackToString.substring(indexOfDelimiter + 1);

    byte[] finalBytes = finalString.getBytes(StandardCharsets.UTF_8);

    System.out.println(finalString.equals(initialString));
    System.out.println(Arrays.equals(initialBytes, finalBytes));
}

输出:

true
true

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-27
    • 2012-02-24
    相关资源
    最近更新 更多