使用Java将十六进制转储的字符串表示形式转换为字节数组?
我正在寻找一种方法来转换长字符串(从转储),该字符串将十六进制值转换为字节数组。
我没有比在这里发表同样问题的人更好的表述了。
但是为了保持其原始性,我将以自己的方式来表述:假设我有一个字符串" 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;
}

