我正在寻找一种方法来转换一个长字符串(从转储),它表示十六进制值到字节数组。
我不可能比在这里发布同样问题的人表达得更好。
但是为了保持它的原创性,我将以自己的方式表达它:假设我有一个字符串“00A0BF”,我希望将其解释为
byte[] {0x00,0xA0,0xBf}
我该怎么办?
我是一个Java新手,最后使用BigInteger并注意前导十六进制零。但我认为它很丑,我肯定我错过了一些简单的东西。
我正在寻找一种方法来转换一个长字符串(从转储),它表示十六进制值到字节数组。
我不可能比在这里发布同样问题的人表达得更好。
但是为了保持它的原创性,我将以自己的方式表达它:假设我有一个字符串“00A0BF”,我希望将其解释为
byte[] {0x00,0xA0,0xBf}
我该怎么办?
我是一个Java新手,最后使用BigInteger并注意前导十六进制零。但我认为它很丑,我肯定我错过了一些简单的东西。
当前回答
一行程序: 进口javax.xml.bind.DatatypeConverter; (字节[]数组) 返回DatatypeConverter.printHexBinary(数组); } public static byte[] toByteArray(String s) { 返回DatatypeConverter.parseHexBinary (s); }
对于那些对来自FractalizeR的一行代码背后的实际代码感兴趣的人(我需要它,因为javax.xml.bind不适用于Android(默认情况下)),这来自com.sun.xml.internal.bind. datatypeconverterimpll .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();
}
其他回答
如果您的需求不仅仅是偶尔的转换,那么您可以使用HexUtils。
例子:
byte[] byteArray = Hex.hexStrToBytes("00A0BF");
这是最简单的情况。您的输入可能包含分隔符(如MAC地址、证书指纹等),您的输入可能是流式的,等等。在这种情况下,引入像HexUtils这样的外部库(无论多么小)变得更容易。
在JDK 17中,HexFormat类将满足大多数需求,而对HexUtils这样的类的需求将大大减少。然而,HexUtils仍然可以用于一些事情,比如从十六进制(流)转换非常大的量或漂亮的十六进制打印(想想有线转储),这是JDK HexFormat类不能做的。
(完全披露:我是HexUtils的作者)
更新(2021年)- Java 17现在包括Java .util. hexformat(只花了25年):
HexFormat.of().parseHex(s)
这里有一个解决方案,我认为比目前为止发布的任何解决方案都要好:
/* s must be an even-length string. */
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或异常添加参数检查。
基于op投票的解决方案,下面的方案应该更有效一些:
public static byte [] hexStringToByteArray (final String s) {
if (s == null || (s.length () % 2) == 1)
throw new IllegalArgumentException ();
final char [] chars = s.toCharArray ();
final int len = chars.length;
final byte [] data = new byte [len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit (chars[i], 16) << 4) + Character.digit (chars[i + 1], 16));
}
return data;
}
因为:到char数组的初始转换省去了charAt中的长度检查
我知道这是一个非常老的帖子,但仍然喜欢添加我的便士价值。
如果我真的需要编码一个简单的十六进制字符串到二进制转换器,我想这样做。
public static byte[] hexToBinary(String s){
/*
* skipped any input validation code
*/
byte[] data = new byte[s.length()/2];
for( int i=0, j=0;
i<s.length() && j<data.length;
i+=2, j++)
{
data[j] = (byte)Integer.parseInt(s.substring(i, i+2), 16);
}
return data;
}
java中的BigInteger()方法。数学很慢,不值得推荐。
整数。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;
}
玩得开心,好运