我正在寻找一种方法来转换一个长字符串(从转储),它表示十六进制值到字节数组。

我不可能比在这里发布同样问题的人表达得更好。

但是为了保持它的原创性,我将以自己的方式表达它:假设我有一个字符串“00A0BF”,我希望将其解释为

byte[] {0x00,0xA0,0xBf}

我该怎么办?

我是一个Java新手,最后使用BigInteger并注意前导十六进制零。但我认为它很丑,我肯定我错过了一些简单的东西。


当前回答

Bert Regelink提出的准则根本不起作用。 试试下面的方法:

import javax.xml.bind.DatatypeConverter;
import java.io.*;

public class Test
{  
    @Test
    public void testObjectStreams( ) throws IOException, ClassNotFoundException
    {     
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);

            String stringTest = "TEST";
            oos.writeObject( stringTest );

            oos.close();
            baos.close();

            byte[] bytes = baos.toByteArray();
            String hexString = DatatypeConverter.printHexBinary( bytes);
            byte[] reconvertedBytes = DatatypeConverter.parseHexBinary(hexString);

            assertArrayEquals( bytes, reconvertedBytes );

            ByteArrayInputStream bais = new ByteArrayInputStream(reconvertedBytes);
            ObjectInputStream ois = new ObjectInputStream(bais);

            String readString = (String) ois.readObject();

            assertEquals( stringTest, readString);
        }
    }

其他回答

下面是一个实际有效的方法(基于之前几个半正确的答案):

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();

编辑:正如海报所指出的,前导零不安全。

现在可以在guava中使用BaseEncoding来实现这一点。

BaseEncoding.base16().decode(string);

反过来使用

BaseEncoding.base16().encode(bytes);

一行程序: 进口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();
}

我知道这是一个非常老的帖子,但仍然喜欢添加我的便士价值。

如果我真的需要编码一个简单的十六进制字符串到二进制转换器,我想这样做。

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