使用Java将十六进制转储的字符串表示形式转换为字节数组?

时间:2020-03-06 14:47:26  来源:igfitidea点击:

我正在寻找一种方法来转换长字符串(从转储),该字符串将十六进制值转换为字节数组。

我没有比在这里发表同样问题的人更好的表述了。

但是为了保持其原始性,我将以自己的方式来表述:假设我有一个字符串" 00A0BF",我想将其解释为

byte[] {0x00,0xA0,0xBf}

我该怎么办?

我是Java新手,最终使用BigInteger并注意前导十六进制零。但是我认为这很丑陋,并且我肯定我缺少一些简单的东西。

解决方案

commons编解码器中的Hex类应该为我们做到这一点。

http://commons.apache.org/codec/

我一直使用类似的方法

public static final byte[] fromHexString(final String s) {
    String[] v = s.split(" ");
    byte[] arr = new byte[v.length];
    int i = 0;
    for(String val: v) {
        arr[i++] =  Integer.decode("0x" + val).byteValue();

    }
    return arr;
}

该方法以空格分隔的十六进制值进行分割,但并不难于根据其他条件(例如将两个字符分组)将字符串分割。

我想会帮你的。我通过一个类似的函数将其拼凑在一起,该函数以字符串形式返回数据:

private static byte[] decode(String encoded) {
    byte result[] = new byte[encoded/2];
    char enc[] = encoded.toUpperCase().toCharArray();
    StringBuffer curr;
    for (int i = 0; i < enc.length; i += 2) {
        curr = new StringBuffer("");
        curr.append(String.valueOf(enc[i]));
        curr.append(String.valueOf(enc[i + 1]));
        result[i] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    return result;
}

编辑:如@mmyers所指出,此方法不适用于包含与设置了高位(" 80"" FF")的字节相对应的子字符串的输入。说明在Bug ID:6259307 Byte.parseByte不能按SDK文档中所宣传的那样工作。

public static final byte[] fromHexString(final String s) {
    byte[] arr = new byte[s.length()/2];
    for ( int start = 0; start < s.length(); start += 2 )
    {
        String thisByte = s.substring(start, start+2);
        arr[start/2] = Byte.parseByte(thisByte, 16);
    }
    return arr;
}

这是一种实际有效的方法(基于先前的一些半正确答案):

private static byte[] fromHexString(final String encoded) {
    if ((encoded.length() % 2) != 0)
        throw new IllegalArgumentException("Input string must contain an even number of characters");

    final byte result[] = new byte[encoded.length()/2];
    final char enc[] = encoded.toCharArray();
    for (int i = 0; i < enc.length; i += 2) {
        StringBuilder curr = new StringBuilder(2);
        curr.append(enc[i]).append(enc[i + 1]);
        result[i/2] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    return result;
}

我看到的唯一可能的问题是输入字符串是否过长。调用toCharArray()会复制字符串的内部数组。

编辑:哦,顺便说一下,字节是用Java签名的,所以输入字符串将转换为[0,-96,-65]而不是[0,160,191]。但是我们可能已经知道了。

实际上,我认为BigInteger解决方案非常好:

new BigInteger("00A0BF", 16).toByteArray();

编辑:如海报所述,对于前导零不安全。

我认为以下解决方案比迄今为止发布的任何解决方案都要好:

public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                             + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

改进的原因:

  • 前导零(与BigInteger不同)和负字节值(与Byte.parseByte不同)是安全的
  • 不会将String转换为char [],也不会为每个字节创建StringBuilder和String对象。
  • 没有可能不可用的库依赖项

如果不确定参数是安全的,可以通过assert或者异常添加参数检查。

java.math的BigInteger()方法非常慢,并且不值得推荐。

Integer.parseInt(HEXString,16)

可能会导致某些字符出现问题,而没有
转换为数字/整数

运作良好的方法:

Integer.decode("0xXX") .byteValue()

功能:

public static byte[] HexStringToByteArray(String s) {
    byte data[] = new byte[s.length()/2];
    for(int i=0;i < s.length();i+=2) {
        data[i/2] = (Integer.decode("0x"+s.charAt(i)+s.charAt(i+1))).byteValue();
    }
    return data;
}

玩得开心,祝你好运

public static byte[] hex2ba(String sHex) throws Hex2baException {
    if (1==sHex.length()%2) {
        throw(new Hex2baException("Hex string need even number of chars"));
    }

    byte[] ba = new byte[sHex.length()/2];
    for (int i=0;i<sHex.length()/2;i++) {
        ba[i] = (Integer.decode(
                "0x"+sHex.substring(i*2, (i+1)*2))).byteValue();
    }
    return ba;
}

我喜欢Character.digit解决方案,但是这是我解决的方法

public byte[] hex2ByteArray( String hexString ) {
    String hexVal = "0123456789ABCDEF";
    byte[] out = new byte[hexString.length() / 2];

    int n = hexString.length();

    for( int i = 0; i < n; i += 2 ) {
        //make a bit representation in an int of the hex value 
        int hn = hexVal.indexOf( hexString.charAt( i ) );
        int ln = hexVal.indexOf( hexString.charAt( i + 1 ) );

        //now just shift the high order nibble and add them together
        out[i/2] = (byte)( ( hn << 4 ) | ln );
    }

    return out;
}