【问题标题】:Convert String to/from byte array without encoding在不编码的情况下将字符串转换为字节数组/从字节数组转换
【发布时间】:2016-06-22 09:28:45
【问题描述】:

我有一个通过网络连接读取的字节数组,我需要将其转换为不带任何编码的字符串,也就是说,只需将每个字节视为字符的低端并将高端设为零。我还需要做相反的事情,我知道角色的高端总是为零。

在网络上搜索会产生几个类似的问题,这些问题都得到了表明必须更改原始数据源的响应。这不是一个选项,所以请不要建议它。

这在 C 中是微不足道的,但 Java 似乎要求我编写自己的转换例程,这可能非常低效。有没有我错过的简单方法?

【问题讨论】:

  • new String(yourByteArray);?
  • 你是如何确定它可能效率很低的?
  • 为什么要转换成字符串?如果你有一个 byte[] 那么你可以保持原样吗?如果您不知道编码,那么您怎么可能希望将这些字节解释为字符串?

标签: java string data-conversion


【解决方案1】:

不,你没有错过任何东西。没有简单的方法可以做到这一点,因为 Stringchar 用于文本。您显然不想将数据作为文本处理——如果它不是文本,这将完全有意义。你可以按照你提议的艰难方式来做。

另一种方法是假设允许任意字节值 (0-255) 的任意序列的字符编码。 ISO-8859-1 或 IBM437 都符合条件。 (Windows-1252 只有 251 个代码点。UTF-8 不允许任意序列。)如果您使用 ISO-8859-1,则生成的字符串将与您的硬方式相同。

至于效率,处理字节数组最有效的方式就是将其保存为字节数组。

【讨论】:

  • 很好的解决方案。 String s = new String(in, "ISO-8859-1");为我工作,但切断了尾随零,所以我认为它与更难的方式并不完全相同
【解决方案2】:

这会将字节数组转换为字符串,同时仅填充高 8 位。

public static String stringFromBytes(byte byteData[]) {
    char charData[] = new char[byteData.length];
    for(int i = 0; i < charData.length; i++) {
        charData[i] = (char) (((int) byteData[i]) & 0xFF);
    }
    return new String(charData);
}

效率应该是相当不错的。就像 Ben Thurley 所说,如果性能确实是这样的问题,请不要首先转换为字符串,而是使用字节数组。

【讨论】:

    【解决方案3】:

    这里是一个示例代码,它将 String 转换为 byte array 并返回到 String 而无需编码。

    public class Test
    {
    
        public static void main(String[] args)
        {
            Test t = new Test();
            t.Test();
        }
    
        public void Test()
        {
            String input = "Hèllo world";
            byte[] inputBytes = GetBytes(input);
            String output = GetString(inputBytes);
            System.out.println(output);
        }
    
        public byte[] GetBytes(String str)
        {
            char[] chars = str.toCharArray();
            byte[] bytes = new byte[chars.length * 2];
            for (int i = 0; i < chars.length; i++)
            {
                bytes[i * 2] = (byte) (chars[i] >> 8);
                bytes[i * 2 + 1] = (byte) chars[i];
            }
    
            return bytes;
        }
    
        public String GetString(byte[] bytes)
        {
            char[] chars = new char[bytes.length / 2];
            char[] chars2 = new char[bytes.length / 2];
            for (int i = 0; i < chars2.length; i++)
                chars2[i] = (char) ((bytes[i * 2] << 8) + (bytes[i * 2 + 1] & 0xFF));
    
            return new String(chars2);
    
        }
    }
    

    【讨论】:

    • 感谢您的建议。我已经实现了一些接近于此的东西,而且一切似乎都运行良好。
    • Java 的String 类有String.getBytes()new String(byte[])
    • 这是使用编码:UTF-16。而且,它可能会创建无效的 UTF-16 代码单元序列,因此您将字符串传递给的任何函数都可以正确地抛出异常,正如 Unicode 规范所建议的那样。
    【解决方案4】:

    使用已弃用的构造函数String(byte[] ascii, int hibyte)

    String string = new String(byteArray, 0);
    

    【讨论】:

      【解决方案5】:

      字符串已被编码为 Unicode/UTF-16。 UTF-16 意味着最多可以使用 2 个字符串“字符”(char) 来生成一个可显示的字符。你真正想要的是使用的是:

      byte[] bytes = System.Text.Encoding.Unicode.GetBytes(myString); 
      

      将字符串转换为字节数组。这与您在上面所做的完全一样,只是性能快了 10 倍。如果您想将传输数据减少近一半,我建议您将其转换为 UTF8(ASCII 是 UTF8 的子集)——互联网 90% 的时间使用的格式,通过调用:

      byte[] bytes = Encoding.UTF8.GetBytes(myString);
      

      要转换回字符串,请使用:

      String myString = Encoding.Unicode.GetString(bytes); 
      

      String myString = Encoding.UTF8.GetString(bytes);
      

      【讨论】:

      • 注意标签。此代码适用于 C#/.NET,但问题标记为 [java]。不过,同样的理由适用,并且库是相似的。欢迎使用 Stack Overflow。
      猜你喜欢
      • 2015-03-15
      • 1970-01-01
      • 1970-01-01
      • 2021-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多