当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《使用Java将十六进制转储的字符串表示形式转换为字节数组?》经验,为你挑选了10个好方法。

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

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

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

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

我该怎么办?

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



1> Dave L...:

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

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转换为a char[],或为每个字节创建StringBuilder和String对象.

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

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


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

2> Vladislav Ra..:

单行:

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);
}

警告:

在Java 9 Jigsaw中,这不再是(默认)java.se根集的一部分,因此它将导致ClassNotFoundException,除非你指定--add-modules java.se.ee(感谢@ eckes)

在Android上不可用(感谢Fabian注意到这一点),但如果您的系统因某些原因缺乏,您可以获取源代码javax.xml.感谢@ Bert Regelink提取源代码.


恕我直言,这应该是接受/最佳答案,因为它简短*干净*(不像@ DaveL的答案)并且不需要任何外部库(如skaffman的答案).此外,*<输入一个关于重新发明自行车的笑话>*.
例如,android中没有datatypeconverter类.
警告:在Java 9 Jigsaw中,这不再是(默认)`java.se`根集的一部分,因此它将导致`ClassNotFoundException`,除非你指定`--add-modules java.se.ee`
@dantebarba我认为`javax.xml.bind.DatatypeConverter`已经提供了一种编码/解码Base64数据的方法.参见`parseBase64Binary()`和`printBase64Binary()`.

3> skaffman..:

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

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

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


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

4> jontro..:

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

BaseEncoding.base16().decode(string);

扭转使用

BaseEncoding.base16().encode(bytes);



5> Dave L...:

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

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

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


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

6> GrkEngineer..:

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;
}

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


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

7> Bert Regelin..:

单行:

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);
}

对于那些你感兴趣的背后的实际代码一行程序从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> 4) & 0xF]);
        r.append(hexCode[(b & 0xF)]);
    }
    return r.toString();
}


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

8> Michael Myer..:

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

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].但你可能已经知道了.



9> Miao1007..:

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

简单用法:

byte[] bytes = ByteString.decodeHex("c000060000").toByteArray();

结果将是

[-64, 0, 6, 0, 0]



10> Sniper..:

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

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;
}

玩得开心,祝你好运

推荐阅读
夏晶阳--艺术
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有