在Java中,如何将十六进制字符串转换为字节数组?

40

我正在使用Java中的以下函数将加密字符串转换为十六进制格式:

public static String toHex(byte [] buf) {
    StringBuffer strbuf = new StringBuffer(buf.length * 2);
    int i;
    for (i = 0; i < buf.length; i++) {
        if (((int) buf[i] & 0xff) < 0x10) {
            strbuf.append("0");
        }
        strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
    }
    return strbuf.toString();
}

现在我想将该十六进制字符串转换回字节数组。我该如何做?

例如,

(1) Plain Text = 123
(2) Encrypted Text = «h>kq*«¬Mí“~èåZ  \}?
(3) Encrypted Text in Hex = f263575e7b00a977a8e9a37e08b9c215feb9bfb2f992b2b8f11e

我可以从(2)走到(3),但如何从(3)回到(2)?


从aa到Ra。One Movie no kamal chhe. 你可以加入我的聊天室http://chat.stackoverflow.com/rooms/6137/ - Lucifer
2
什么是“Back byte array”?它和“byte array”有什么不同? - Keith Irwin
如何将二进制/字节字符串转换为十六进制? http://stackoverflow.com/questions/29603046/decrypt-string-in-java-which-was-encrypted-using-symmetric-key-in-php/29603246?noredirect=1#29603046 - Scorpion
3个回答

114

被接受的答案没有考虑前导零可能会导致问题

这个问题 回答了它。根据您是想看看如何完成还是只使用Java内置方法,以下是从所提到的SO问题中分别复制的解决方案:选项1选项2

选项1:Util方法

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

选项2:一行内置代码

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

你的回答帮助了我,链接是https://dev59.com/HEfRa4cB1Zd3GeqP94g5#25790612,谢谢+1。 - gavenkoa
使用Java已提供的类,对于一行代码的选项加1。 - Zeimyth
对于字符串56276BE1,它给出了字节86, 39, 107, -31。但是另一个用C#编写的应用程序给出了相同十六进制字符串的86, 39, 107, 225。哪一个是正确的? - Fer
两种都是正确的。C#处理字节与Java不同。在Java中,字节值介于-127和127之间,而C#则为0到255。 - dARKpRINCE
4
然而,在Java 9上,看起来内置的一行代码似乎不再像以前那样内置了,因为仅仅导入 javax.xml.bind.DatatypeConverter 并不能正常工作。 - ionizer
1
从Java 17开始,现在官方提供了一个方法 java.util.HexFormat.of().parseHex(s) - Dave L.

47
 String s="f263575e7b00a977a8e9a37e08b9c215feb9bfb2f992b2b8f11e";
 byte[] b = new BigInteger(s,16).toByteArray();

6
这并没有给我想要的结果,但是dARKpRINCE回复中简单的一行代码方法却成功了。 - Jeremy Goodell
cs.setBytes(1,new BigInteger(regReportId,16).toByteArray()); 当我需要将RAW数据类型传递给Oracle存储过程时,这段代码是有效的。 - Dilip
new BigInteger(s,16).toByteArray(); 这个方法不正确。我输入了一个长度为34的十六进制字符串,输出却是18个字节。我需要的是17个字节。 - Ninja
我认为有时候这会给出错误的结果。例如,对于A85565ED63B893F5A3EF85D88819D484,它会给出17个字节。但实际上应该是16个字节。 - Adem
这会给出错误的结果;DarkPrince的“util方法”对我来说是有效的。 - Blisterpeanuts

6

我发现DatatypeConverter.parseHexBinary的成本比以下方法更高(两倍):

org.apache.commons.codec.binary.Hex(str.toCharArray())

这比DatatypeConverter更昂贵,因为Apache commons是一个额外的库(依赖项、大小等)- 而DatatypeConverter是JDK的一部分。 - foo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接