【问题标题】:Converting String to bytes in java [duplicate]在java中将字符串转换为字节[重复]
【发布时间】:2012-11-22 23:25:48
【问题描述】:

可能重复:
Convert a string representation of a hex dump to a byte array using Java?

我想将 String "1B4322C2" 转换为字节,但问题是如果我使用 getBytes() 它会将其转换为字符串长度的两倍,我想将它们转换为字符串长度的一半。

例如以上字符串的输出应该是{0x1B , 0x43, 0x22, 0xC2}

谢谢

【问题讨论】:

  • 字符串总是8个字符吗?

标签: java byte bytebuffer


【解决方案1】:

要将“1B4322C2”编码为字节,您可以使用

byte[] bytes = new BigInteger("FB4322C2", 16).toByteArray();
if (bytes.length > 1 && bytes[0] == 0)
    bytes = Arrays.copyOfRange(bytes, 1, bytes.length);
System.out.println(Arrays.toString(bytes));

打印

[-5, 67, 34, -62]

【讨论】:

    【解决方案2】:

    您不需要 String.getBytes() 方法。这会将字符串的字符转换为它们的字节表示形式。

    要执行您想要执行的操作,您需要手动将字符串拆分为单独的字符串,每对一个字符串。然后,您将要解析它们。

    不幸的是,Java 没有无符号字节,0xC2 会溢出。如果内存不是问题,您可能希望将这些值视为短裤或整数。

    因此,您可以使用 Integer 类将字符串解析为数字。由于您的字符串是十六进制的,因此您必须使用可让您提供基数的 parse 方法。

    String test = "1B4322C2";
    
    for (int bnum = 0; bnum < test.length() / 2; bnum++) {
        String bstring = test.substring(bnum * 2, bnum * 2 + 2);
        int bval = Integer.parseInt(bstring, 16);
        System.out.println(bstring + " -> " + bval);
    }
    

    这将输出:

    1B -> 27
    43 -> 67
    22 -> 34
    C2 -> 194
    

    如果您需要将它们放在数组中,您可以实例化一个宽度为字符串一半的数组,然后它们将每个值放在其bnum 索引下。

    【讨论】:

    • Java doesn't have unsigned bytes, and 0xC2 is going to overflow. 绝对的废话。没有溢出。试试byte b = 0xC2; 它可以工作。
    【解决方案3】:

    (我现在已经投票决定以重复的形式关闭,我应该先这样做......但是在问题被删除之前将这个答案留在这里是有意义的......)

    对,所以你实际上想要做的是解析一个十六进制字符串。

    您应该查看Apache Commons Codec,它有一个Hex 类正是为了这个目的。就我个人而言,我对 API 并不感兴趣,但这应该可行:

    Hex hex = new Hex();
    byte[] data = (byte[]) hex.decode(text);
    

    或者:

    byte[] data = Hex.decodeHex(text.toCharArray());
    

    (我个人希望你可以使用byte[] data = Hex.decodeHexString(text);,但我们开始了......如果你愿意,你可以随时编写自己的包装方法。)

    如果您不想使用 3rd 方库,则 Stack Overflow 上的其他地方有很多实现,例如this one.

    【讨论】:

    • 你可以使用Byte.parseByte(str,16);
    • @Quoi:嗯,这需要为每个字节创建一个新的String 对象。我认为我们不需要那么低效。
    • 我们为什么要向 Apache Commons 发送 Java 开头?这可以使用基本数字原始包装类来处理。编辑:哦等等,这家伙不是java初学者。本来可以骗我的。继续。
    • @JonSkeet - 类似if ((str.length() % 2) == 1) str = "0" + str; for(int i=0;i&lt;str.length()-1;){ String str1 = str.substring(i, i+2); System.out.print(Byte.parseByte(str1,16)); i+=2; }
    • @Chris:即使对于初学者来说,很多事情当然可以在没有第三方库的情况下实现,但不应该——为什么要重新发明一个已经在其他地方有效发明的轮子?我认为寻找解决问题的现有库是我们应该积极教给初学者的东西。 (Guava 和 Joda Time 是我首先引导人们访问的图书馆 :)
    【解决方案4】:

    如果您不想使用外部库,这应该通过一些调整来解决问题(添加 0x 和 { })

    public static String byteArrayToHexadecimal(byte[] raw) {
        final BigInteger bi = new BigInteger(1, raw);
        final String result = bi.toString(16);
        if (result.length() % 2 != 0) {
            return "0" + result;
        }
        return result;
    }
    

    抱歉,换个方式(没有优化,因为对我来说根本不是瓶颈):

    public static byte[] hexadecimalToByteArray(String hex) {
        if (hex.length() % 2 != 0) {
            hex = "0" + hex;
        }
        final byte[] result = new byte[hex.length() / 2];
        for (int i = 0; i < hex.length(); i += 2) {
            String sub = "0x" + hex.substring(i, i + 2);
            result[i / 2] = (byte) ((int) Integer.decode(sub));
        }
        return result;
    }
    

    不过,我建议按照 J. Skeet 的建议选择 Apache Commons Codec

    【讨论】:

    • OP 想要反过来,但我承认BigInteger 的使用很巧妙。
    • 请注意,这与 OP 想要的方向相反,我个人不会使用 BigInteger 进行十六进制转换 - 这不是它的设计目的,它通常会削减前导0。 (例如,使用上面的代码,{ 0, 0, 0 } 应该给出“000000”,但我相信它只会给出“00”。)
    【解决方案5】:

    您可以使用 String Tokenizer 或 String Builder 并分离字符串,然后将其从十六进制转换为字符串...

    此链接可能对您有所帮助..
    Convert Hex to ASCII

    希望这会有所帮助..

    【讨论】:

      【解决方案6】:

      getBytes将每个字符转换为字节形式的字符代码;它不会从字符串本身解析出字节值。为此,您可能需要编写自己的解析函数。

      【讨论】:

        猜你喜欢
        • 2012-06-02
        • 1970-01-01
        • 2012-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-22
        相关资源
        最近更新 更多