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

raf*_*raf 353 java hex byte dump

我正在寻找一种方法来转换长字符串(从转储),它表示十六进制值到一个字节数组.

我不能比在这里发布相同问题的人更好地措辞.

但为了保持原创,我会用自己的方式来表达它:假设我有一个"00A0BF"我想要解释为的字符串

byte[] {0x00,0xA0,0xBf}
Run Code Online (Sandbox Code Playgroud)

我该怎么办?

我是Java新手,最后使用BigInteger并注意领先的十六进制零.但我觉得它很难看,我确信我错过了一些简单的东西.

Dav*_* L. 609

这是一个我认为比目前任何发布的解决方案更好的解决方案:

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;
}
Run Code Online (Sandbox Code Playgroud)

这是一个改进的原因:

  • 带前导零的安全(与BigInteger不同)和负字节值(与Byte.parseByte不同)

  • 不将String转换为a char[],或为每个字节创建StringBuilder和String对象.

  • 没有可能不可用的库依赖项

assert如果不知道参数是否安全,可以随意添加参数检查或异常.

  • "0"无效输入.字节每个需要两个十六进制数字.正如答案所指出的那样,"如果不知道这个论点是安全的,请随意添加参数检查." (46认同)
  • 在我的微测试中,javax.xml.bind.DatatypeConverter.parseHexBinary(hexString)似乎比上述解决方案快20%左右(无论价值多少),以及在无效输入上正确抛出异常(例如"gg")不是有效的hexString,但会使用建议的解决方案返回-77). (11认同)
  • @DaedalusAlpha这取决于你的背景,但通常我发现用这些东西快速和大声地失败是更好的,这样你就可以修复你的假设,而不是默默地返回不正确的数据. (6认同)
  • 它不适用于字符串"0".它抛出java.lang.StringIndexOutOfBoundsException (4认同)
  • 你能给出一个解码不正确的例子,或解释它是怎么回事吗? (2认同)

Vla*_*sny 325

单行:

import javax.xml.bind.DatatypeConverter;

public static String toHexString(byte[] array) {
    return DatatypeConverter.printHexBinary(array);
}

public static byte[] toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s);
}
Run Code Online (Sandbox Code Playgroud)

警告:

  • 在Java 9 Jigsaw中,这不再是(默认)java.se根集的一部分,因此它将导致ClassNotFoundException,除非你指定--add-modules java.se.ee(感谢@ eckes)
  • 在Android上不可用(感谢Fabian注意到这一点),但如果您的系统因某些原因缺乏,您可以获取源代码javax.xml.感谢@ Bert Regelink提取源代码.

  • 恕我直言,这应该是接受/最佳答案,因为它简短*干净*(不像@ DaveL的答案)并且不需要任何外部库(如skaffman的答案).此外,*<输入一个关于重新发明自行车的笑话>*. (13认同)
  • 例如,android中没有datatypeconverter类. (8认同)
  • 警告:在Java 9 Jigsaw中,这不再是(默认)`java.se`根集的一部分,因此它将导致`ClassNotFoundException`,除非你指定`--add-modules java.se.ee` (4认同)
  • @dantebarba我认为`javax.xml.bind.DatatypeConverter`已经提供了一种编码/解码Base64数据的方法.参见`parseBase64Binary()`和`printBase64Binary()`. (2认同)
  • 为了增加 DataTypeConverter 的问题,Java SE 11 完全删除了 JAXB API,现在只包含在 Java EE 中。您还可以将其添加为 Maven 依赖项,如下所示:/sf/answers/3050209921/ (2认同)

ska*_*man 75

commons-codec中的Hex类应该为你做.

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

import org.apache.commons.codec.binary.Hex;
...
byte[] decoded = Hex.decodeHex("00A0BF");
// 0x00 0xA0 0xBF
Run Code Online (Sandbox Code Playgroud)

  • 这看起来也不错.请参阅org.apache.commons.codec.binary.Hex.decodeHex() (5认同)

jon*_*tro 36

您现在可以使用BaseEncodingguava做到这一点.

BaseEncoding.base16().decode(string);
Run Code Online (Sandbox Code Playgroud)

扭转使用

BaseEncoding.base16().encode(bytes);
Run Code Online (Sandbox Code Playgroud)


Dav*_* L. 27

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

new BigInteger("00A0BF", 16).toByteArray();
Run Code Online (Sandbox Code Playgroud)

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

  • BigInteger的问题是必须有一个"符号位".如果前导字节的高位设置,则结果字节数组在第1个位置有一个额外的0.但仍然是+1. (3认同)
  • 这是领先0的好点.我不确定我是否认为它可能会混淆字节的顺序,并且非常有兴趣看到它的演示. (2认同)

Grk*_*eer 24

HexBinaryAdapter规定之间编组和取消编组的能力Stringbyte[].

import javax.xml.bind.annotation.adapters.HexBinaryAdapter;

public byte[] hexToBytes(String hexString) {
     HexBinaryAdapter adapter = new HexBinaryAdapter();
     byte[] bytes = adapter.unmarshal(hexString);
     return bytes;
}
Run Code Online (Sandbox Code Playgroud)

这只是我输入的一个例子......我实际上只是按原样使用它,不需要单独使用它.

  • 您可以直接使用java.xml.bind.DatatypeConverter.parseHexBinary(hexString)而不是使用HexBinaryAdapter(后者又调用DatatypeConverter).这样您就不必创建适配器实例对象(因为DatatypeConverter方法是静态的). (8认同)
  • 仅当输入字符串(hexString)具有偶数个字符时,它才有效.否则:线程"main"中的异常java.lang.IllegalArgumentException:hexBinary需要是偶数长度: (5认同)
  • 哦,谢谢你指出这一点.用户实际上不应该有奇数个字符,因为字节数组表示为{0x00,0xA0,0xBf}.每个字节有两个十六进制数字或半字节.因此,任何数量的字节应始终具有偶数个字符.谢谢你提到这个. (3认同)

Ber*_*ink 24

单行:

import javax.xml.bind.DatatypeConverter;

public static String toHexString(byte[] array) {
    return DatatypeConverter.printHexBinary(array);
}

public static byte[] toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s);
}
Run Code Online (Sandbox Code Playgroud)

对于那些你感兴趣的背后的实际代码一行程序FractalizeR(我需要的,因为javax.xml.bind中没有可用于Android(默认)),这个来自com.sun.xml.internal.bind. DatatypeConverterImpl.java:

public byte[] parseHexBinary(String s) {
    final int len = s.length();

    // "111" is not a valid hex encoding.
    if( len%2 != 0 )
        throw new IllegalArgumentException("hexBinary needs to be even-length: "+s);

    byte[] out = new byte[len/2];

    for( int i=0; i<len; i+=2 ) {
        int h = hexToBin(s.charAt(i  ));
        int l = hexToBin(s.charAt(i+1));
        if( h==-1 || l==-1 )
            throw new IllegalArgumentException("contains illegal character for hexBinary: "+s);

        out[i/2] = (byte)(h*16+l);
    }

    return out;
}

private static int hexToBin( char ch ) {
    if( '0'<=ch && ch<='9' )    return ch-'0';
    if( 'A'<=ch && ch<='F' )    return ch-'A'+10;
    if( 'a'<=ch && ch<='f' )    return ch-'a'+10;
    return -1;
}

private static final char[] hexCode = "0123456789ABCDEF".toCharArray();

public String printHexBinary(byte[] data) {
    StringBuilder r = new StringBuilder(data.length*2);
    for ( byte b : data) {
        r.append(hexCode[(b >> 4) & 0xF]);
        r.append(hexCode[(b & 0xF)]);
    }
    return r.toString();
}
Run Code Online (Sandbox Code Playgroud)

  • 默认情况下,Java 9中也不提供DatatypeConverter.危险的是使用它的代码将在Java 1.8或更早版本(Java 9,源代码设置更早)下编译,但在没有"--add-modules java.se.ee"的Java 9下获得运行时异常. (2认同)

Mic*_*ers 14

这是一种实际工作的方法(基于以前的几个半正确答案):

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;
}
Run Code Online (Sandbox Code Playgroud)

我能看到的唯一可能的问题是输入字符串是否非常长; 调用toCharArray()会生成字符串内部数组的副本.

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


Mia*_*007 11

在android中,如果你正在使用hex,你可以尝试okio.

简单用法:

byte[] bytes = ByteString.decodeHex("c000060000").toByteArray();
Run Code Online (Sandbox Code Playgroud)

结果将是

[-64, 0, 6, 0, 0]
Run Code Online (Sandbox Code Playgroud)


Bla*_*rad 7

编辑:正如@mmyers所指出的,此方法不适用于包含与高位集(“80”-“FF”)的字节相对应的子字符串的输入。错误 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;
}
Run Code Online (Sandbox Code Playgroud)


Sni*_*per 5

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

Integer.parseInt(HEXString, 16)

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

运作良好的方法:

Integer.decode("0xXX") .byteValue()
Run Code Online (Sandbox Code Playgroud)

功能:

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;
}
Run Code Online (Sandbox Code Playgroud)

玩得开心,祝你好运


Con*_*son 5

无论如何,这里有另一个版本,它支持奇数长度字符串,而无需诉诸字符串连接。

public static byte[] hexStringToByteArray(String input) {
    int len = input.length();

    if (len == 0) {
        return new byte[] {};
    }

    byte[] data;
    int startIdx;
    if (len % 2 != 0) {
        data = new byte[(len / 2) + 1];
        data[0] = (byte) Character.digit(input.charAt(0), 16);
        startIdx = 1;
    } else {
        data = new byte[len / 2];
        startIdx = 0;
    }

    for (int i = startIdx; i < len; i += 2) {
        data[(i + 1) / 2] = (byte) ((Character.digit(input.charAt(i), 16) << 4)
                + Character.digit(input.charAt(i+1), 16));
    }
    return data;
}
Run Code Online (Sandbox Code Playgroud)