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