字符串到 byte[] 的转换问题

String to byte[] conversion issue

我正在尝试将字节数组转换为字符串,然后再转换回字节数组。第一部分(byte[] 到字符串)有效,当我尝试将字符串转换回字节数组然后将我得到的与初始字节数组进行比较时,我发现它们是不同的。我猜这是一个编码问题,我尝试了不同的解决方案(使用 UTF-8、ISO-8859-1、UTF-16LE 等),但 none 似乎有效。

有大神知道怎么解决这个问题吗? 提前致谢

Path path = Paths.get("C:\folder1", "profil1.bmp");

        try {

            //file to byte[] 
            byte[] byte_array = Files.readAllBytes(path);
            System.out.println(Arrays.toString(byte_array ));

            //byte[] to string
            String byte_string = Arrays.toString(byte_array); 

            //String to byte[]
            byte[] string_byte = byte_string.getBytes();

            System.out.println(Arrays.equals(byte_array, string_byte));

        } catch (IOException e) {
            System.out.println(e);
        }

这是输出:(结果太长,所以我剪掉了一部分)

[66, 77, -10, -44, 1, 0, 0, 0, 0, 0, 1, -1, ....... ,-1]
false

Arrays.toString(byte[]) 不仅将 byte[] 转换为字符串,还将其转换为 人类可读的 格式。然后,当您对该字符串调用 getBytes() 时,它会将表示原始字节信息的字符连同括号和逗号等格式化字符一起转换为字节 []。

如果您想从 byte[] 创建 String,请使用采用 byte[] 的 String 构造函数显式创建包含您的数据的 String 对象:

    ...
    //byte[] to string
    String byte_string = new String(byte_array);

    //String to byte[]
    byte[] string_byte = byte_string.getBytes();

    System.out.println(Arrays.equals(byte_array, string_byte));

正如其他人所指出的,并非所有二进制数据都在所有字符集中清晰地表示,因此您可以通过显式指定编码来进行转换。

例如,当我尝试对可执行程序文件 (.exe) 进行编码时,上面的示例代码仍然输出 false,但如果我指定 ISO_8859_1 编码,则比较为 true :

    //byte[] to string
    String byte_string = new String(byte_array, StandardCharsets.ISO_8859_1);

    //String to byte[]
    byte[] string_byte = byte_string.getBytes(StandardCharsets.ISO_8859_1);

    System.out.println(Arrays.equals(byte_array, string_byte));

将数据转换为字符串并返回的绝对最安全的方法是使用 this answer 所建议的 base64 编码:

    //file to byte[] 
    byte[] byte_array = Files.readAllBytes(path);
    byte[] encoded = Base64.encodeBase64(byte_array);

    //byte[] to string
    String byte_string = new String(encoded, StandardCharsets.US_ASCII);

    //String to byte[]
    byte[] string_byte = byte_string.getBytes(StandardCharsets.US_ASCII);
    byte[] decoded = Base64.decodeBase64(string_byte);

    System.out.println(Arrays.equals(byte_array, decoded));

Char/String 在设计上包含 Unicode 文本(与其他语言相反)。 这意味着他们

  • 始终使用(字节的)编码来回转换为二进制数据 (byte[]);
  • 如果字节格式不正确,则无法保存任何二进制数据
  • 可以混合使用多个脚本 Latin/Cyrillic/Arabic/symbols。

所以:

byte[] b = s.getBytes(StandardCharsets.UTF_8);
s = new String(b, StandardCharsets.UTF_8);

如果没有 charset 参数,则使用默认编码,具体取决于平台。 转换可能会将占位符替换为不可表示的字符,或者二进制数据可能完全不正确。

文本(String/char)与二进制数据(字节)完全分开。也不是 char 是 2 个字节的 UTF-16BE,而 byte 是 1 个字节。