我有一个字节数组充满十六进制数字和打印它的简单方式是相当没有意义的,因为有许多不可打印的元素。我需要的是精确的十六进制形式:3a5f771c


当前回答

在这一页上找不到任何解决方案吗

使用循环 使用javax.xml.bind.DatatypeConverter,它编译良好,但经常在运行时抛出java.lang.NoClassDefFoundError。

这里有一个解决方案,它没有上面的缺陷(不保证我的没有其他缺陷)

import java.math.BigInteger;

import static java.lang.System.out;
public final class App2 {
    // | proposed solution.
    public static String encode(byte[] bytes) {          
        final int length = bytes.length;

        // | BigInteger constructor throws if it is given an empty array.
        if (length == 0) {
            return "00";
        }

        final int evenLength = (int)(2 * Math.ceil(length / 2.0));
        final String format = "%0" + evenLength + "x";         
        final String result = String.format (format, new BigInteger(bytes));

        return result;
    }

    public static void main(String[] args) throws Exception {
        // 00
        out.println(encode(new byte[] {})); 

        // 01
        out.println(encode(new byte[] {1})); 

        //203040
        out.println(encode(new byte[] {0x20, 0x30, 0x40})); 

        // 416c6c20796f75722062617365206172652062656c6f6e6720746f2075732e
        out.println(encode("All your base are belong to us.".getBytes()));
    }
}   

我不能在62个操作码下得到这个,但如果你可以在第一个字节小于0x10的情况下没有0填充,那么下面的解决方案只使用23个操作码。真正展示了“容易实现自己”的解决方案,如“如果字符串长度为奇数,则填充为零”,如果本机实现还不可用(或者在本例中,如果BigInteger在toString中有一个以零作为前缀的选项),则可能会非常昂贵。

public static String encode(byte[] bytes) {          
    final int length = bytes.length;

    // | BigInteger constructor throws if it is given an empty array.
    if (length == 0) {
        return "00";
    }

    return new BigInteger(bytes).toString(16);
}

其他回答

为了完整起见,一个番石榴解决方案:

import com.google.common.io.BaseEncoding;
...
byte[] bytes = "Hello world".getBytes(StandardCharsets.UTF_8);
final String hex = BaseEncoding.base16().lowerCase().encode(bytes);

现在十六进制是“48656c6c6f20776f726c64”。

Converts bytes data to hex characters

@param bytes byte array to be converted to hex string
@return byte String in hex format

private static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for (int j = 0; j < bytes.length; j++) {
        v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

Apache Commons Codec库有一个Hex类用于完成这种类型的工作。

import org.apache.commons.codec.binary.Hex;

String foo = "I am a string";
byte[] bytes = foo.getBytes();
System.out.println( Hex.encodeHexString( bytes ) );
private static String bytesToHexString(byte[] bytes, int length) {
        if (bytes == null || length == 0) return null;

        StringBuilder ret = new StringBuilder(2*length);

        for (int i = 0 ; i < length ; i++) {
            int b;

            b = 0x0f & (bytes[i] >> 4);
            ret.append("0123456789abcdef".charAt(b));

            b = 0x0f & bytes[i];
            ret.append("0123456789abcdef".charAt(b));
        }

        return ret.toString();
    }
public static String toHexString(byte[] bytes) {

    StringBuilder sb = new StringBuilder();

    if (bytes != null) 
        for (byte b:bytes) {

            final String hexString = Integer.toHexString(b & 0xff);

            if(hexString.length()==1)
                sb.append('0');

            sb.append(hexString);//.append(' ');
        }

      return sb.toString();//.toUpperCase();
}

使用DatatypeConverter:

public String toHexString(byte... bytes) {

    return Optional.ofNullable(bytes)
            .filter(bs->bs.length>0)
            .map(DatatypeConverter::printHexBinary)
            .map(str->IntStream.range(0, str.length())
                    .filter(i->(i%2)==0)        // take every second index
                    .mapToObj(i->"0x" + str.substring(i, i+2))
                    .collect(Collectors.joining(" ")))
            .orElse("");
}