我正在寻找一种方法来转换一个长字符串(从转储),它表示十六进制值到字节数组。
我不可能比在这里发布同样问题的人表达得更好。
但是为了保持它的原创性,我将以自己的方式表达它:假设我有一个字符串“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();
}
其他回答
更新(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或异常添加参数检查。
实际上,我认为BigInteger是很好的解决方案:
new BigInteger("00A0BF", 16).toByteArray();
编辑:正如海报所指出的,前导零不安全。
现在可以在guava中使用BaseEncoding来实现这一点。
BaseEncoding.base16().decode(string);
反过来使用
BaseEncoding.base16().encode(bytes);
我发现内核恐慌有解决方案对我最有用,但遇到问题,如果十六进制字符串是一个奇数。是这样解决的:
boolean isOdd(int value)
{
return (value & 0x01) !=0;
}
private int hexToByte(byte[] out, int value)
{
String hexVal = "0123456789ABCDEF";
String hexValL = "0123456789abcdef";
String st = Integer.toHexString(value);
int len = st.length();
if (isOdd(len))
{
len+=1; // need length to be an even number.
st = ("0" + st); // make it an even number of chars
}
out[0]=(byte)(len/2);
for (int i =0;i<len;i+=2)
{
int hh = hexVal.indexOf(st.charAt(i));
if (hh == -1) hh = hexValL.indexOf(st.charAt(i));
int lh = hexVal.indexOf(st.charAt(i+1));
if (lh == -1) lh = hexValL.indexOf(st.charAt(i+1));
out[(i/2)+1] = (byte)((hh << 4)|lh);
}
return (len/2)+1;
}
我添加了一个十六进制数的数组,所以我通过引用我正在使用的数组,和int我需要转换和返回下一个十六进制数的相对位置。所以最后的字节数组有[0]个十六进制对,[1…十六进制对,然后是对的数目…
一行程序:
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,除非您指定 ——添加模块java.se.ee(感谢@eckes) Android上不支持(感谢Fabian注意到这一点),但如果您的系统由于某种原因缺少javax.xml,您可以只使用源代码。感谢@Bert Regelink提取源代码。