我正在寻找一种方法来转换长字符串(从转储),它表示十六进制值到一个字节数组.
我不能比在这里发布相同问题的人更好地措辞.
但为了保持原创,我会用自己的方式来表达它:假设我有一个"00A0BF"
我想要解释为的字符串
byte[] {0x00,0xA0,0xBf}
我该怎么办?
我是Java新手,最后使用BigInteger
并注意领先的十六进制零.但我觉得它很难看,我确信我错过了一些简单的东西.
这是一个我认为比目前任何发布的解决方案更好的解决方案:
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
如果不知道参数是否安全,可以随意添加参数检查或异常.
单行:
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
提取源代码.
commons-codec中的Hex类应该为你做.
http://commons.apache.org/codec/
import org.apache.commons.codec.binary.Hex; ... byte[] decoded = Hex.decodeHex("00A0BF"); // 0x00 0xA0 0xBF
您现在可以使用BaseEncoding在guava
做到这一点.
BaseEncoding.base16().decode(string);
扭转使用
BaseEncoding.base16().encode(bytes);
实际上,我认为BigInteger解决方案非常好:
new BigInteger("00A0BF", 16).toByteArray();
编辑:正如海报所述,对于前导零不安全.
该HexBinaryAdapter
规定之间编组和取消编组的能力String
和byte[]
.
import javax.xml.bind.annotation.adapters.HexBinaryAdapter; public byte[] hexToBytes(String hexString) { HexBinaryAdapter adapter = new HexBinaryAdapter(); byte[] bytes = adapter.unmarshal(hexString); return bytes; }
这只是我输入的一个例子......我实际上只是按原样使用它,不需要单独使用它.
单行:
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(); }
这是一种实际工作的方法(基于以前的几个半正确答案):
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].但你可能已经知道了.
在android中,如果你正在使用hex,你可以尝试okio.
简单用法:
byte[] bytes = ByteString.decodeHex("c000060000").toByteArray();
结果将是
[-64, 0, 6, 0, 0]
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; }
玩得开心,祝你好运