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


当前回答

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

其他回答

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

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

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

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

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

最简单的解决方案,没有外部库,没有数字常量:

public static String byteArrayToHex(byte[] a) {
   StringBuilder sb = new StringBuilder(a.length * 2);
   for(byte b: a)
      sb.append(String.format("%02x", b));
   return sb.toString();
}

HexFormat是在Java 17中加入的:

String hex = HexFormat.of().formatHex(array);

我们不需要使用任何外部库,也不需要基于循环和常量编写代码。 这样就够了:

byte[] theValue = .....
String hexaString = new BigInteger(1, theValue).toString(16);