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


当前回答

最近我必须实现一个十六进制转换器,以十六进制格式将字节流转储到日志中。最初我是用海克斯做的。encodeHex已经在这里讨论过了。

但是如果你想以一种非常美观/可读的方式来表示字节数组,io.netty.buffer库可能是一个很好的用途,因为它打印出十六进制以及其中的字符串,消除了不可打印的字符。

要求是这样的,

0010   56 56 09 35 32 f0 b2 00 50 4c 45 41 53 45 20 52   VV.52...PLEASE R
0020   45 2d 45 4e 54 45 52 20 4c 41 53 54 20 54 52 41   E-ENTER LAST TRA
0030   4e 53 41 43 54 49 4f 4e 00 04                     NSACTION..

使用io.netty.buffer以一种更美观的方式做到这一点的最短方法是

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;

void hexDump(byte[] buf) {
    ByteBuf byteBuf = Unpooled.wrappedBuffer(buf);
    log.trace("Bytes received (Hex)\n" + ByteBufUtil.prettyHexDump(byteBuf.slice()));
}

如果您正在使用maven,请在pom.xml中包含以下依赖项(在netty页面中检查最新版本)

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-buffer</artifactId>
    <version>4.1.68.Final</version>
</dependency>

输出是:

         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000010| 40 40 b3 f3 80 f3 80 f3 80 f1 48 f1 41 f1 4e f1 |@@........H.A.N.|
|00000020| 47 f1 49 f1 4e f1 47 b5 f1 52 f1 4f f1 43 f1 4b |G.I.N.G..R.O.C.K|
|00000030| f3 80 f3 80 41 b4 40 40 f3 80 f3 80 40 f3 80 04 |....A.@@....@...|
+--------+-------------------------------------------------+----------------+

供您参考,使用答案中讨论的方法的长期方法(可能不是最有效的)是:

public static String hexDump(byte[] buf) throws DecoderException
{
    ByteBuffer byteBuf = ByteBuffer.wrap(buf);
    char[] result = Hex.encodeHex(byteBuf);

    String bin = new String(result).toUpperCase();
    String str = new String(Hex.decodeHex(bin), StandardCharsets.UTF_8);

    str = str.replaceAll("[^!-~]", ".");
    StringBuilder out = new StringBuilder();
    int bytes_per_line = 16;

    for (int pos = 0; pos < str.length(); pos += bytes_per_line) {
        out.append(String.format("%04X   ", pos));
        if (2 * (pos + bytes_per_line) >= bin.length()) {
            out.append(String.format("%-" + 2 * bytes_per_line + "s", bin.substring(2 * pos)).replaceAll("..", "$0 "));
        } else {
            out.append(bin.substring(2 * pos, 2 * (pos + bytes_per_line)).replaceAll("..", "$0 "));
        }
        out.append("   ");
        if (pos + bytes_per_line > str.length()) {
            out.append(str.substring(pos));

        } else {
            out.append(str.substring(pos, pos + bytes_per_line));
        }
        out.append("\n");
    }

    return out.toString();
}

其他回答

我通常使用以下方法进行debuf语句,但我不知道这是否是最好的方法

private static String digits = "0123456789abcdef";

public static String toHex(byte[] data){
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i != data.length; i++)
    {
        int v = data[i] & 0xff;
        buf.append(digits.charAt(v >> 4));
        buf.append(digits.charAt(v & 0xf));
    }
    return buf.toString();
}
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();
    }

javax.xml.bind.DatatypeConverter.printHexBinary()方法是用于XML绑定的Java体系结构(JAXB)的一部分,是将字节[]转换为十六进制字符串的方便方法。DatatypeConverter类还包括许多其他有用的数据操作方法。

在Java 8和更早的版本中,JAXB是Java标准库的一部分。它在Java 9中被弃用,在Java 11中被移除,这是将所有Java EE包移动到它们自己的库中的努力的一部分。说来话长。现在,javax.xml.bind还不存在,如果希望使用包含DatatypeConverter的JAXB,则需要从Maven安装JAXB API和JAXB运行时。

使用示例:

byte bytes[] = {(byte)0, (byte)0, (byte)134, (byte)0, (byte)61};
String hex = javax.xml.bind.DatatypeConverter.printHexBinary(bytes);

会导致:

000086003D

这个和这个答案是一样的。

使用DataTypeConverter classjavax.xml.bind.DataTypeConverter

String hexString = DatatypeConverter。printHexBinary(原始字节[]);

Java 17最终包含HexFormat类,所以你可以简单地做:

HexFormat.of().formatHex(bytes);

它支持配置为小写/大写,分隔符,前缀,后缀等。