Java代码将字节转换为十六进制


Answers:


311
    byte[] bytes = {-1, 0, 1, 2, 3 };
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
        sb.append(String.format("%02X ", b));
    }
    System.out.println(sb.toString());
    // prints "FF 00 01 02 03 "

也可以看看

  • java.util.Formatter 句法
    • %[flags][width]conversion
      • 标记'0'-结果将补零
      • 宽度 2
      • 转换'X'-结果格式为十六进制整数,大写

查看问题的文本,这也可能是所要求的:

    String[] arr = {"-1", "0", "10", "20" };
    for (int i = 0; i < arr.length; i++) {
        arr[i] = String.format("%02x", Byte.parseByte(arr[i]));
    }
    System.out.println(java.util.Arrays.toString(arr));
    // prints "[ff, 00, 0a, 14]"

这里使用几个答案Integer.toHexString(int);这是可行的,但有一些警告。由于参数是an int,因此对参数执行了扩展的原始转换byte,这涉及符号扩展。

    byte b = -1;
    System.out.println(Integer.toHexString(b));
    // prints "ffffffff"

byte用Java签名的8位符号扩展为32位int。为了有效地撤销此符号扩展,可以掩盖byte0xFF

    byte b = -1;
    System.out.println(Integer.toHexString(b & 0xFF));
    // prints "ff"

使用的另一个问题toHexString是它不填充零:

    byte b = 10;
    System.out.println(Integer.toHexString(b & 0xFF));
    // prints "a"

两种因素的结合应使 String.format解决方案将更可取。

参考文献


@Vivek:什么是“巨大的价值”?输入是什么,输出是什么?
polygenelubricants 2010年

让我再次解释..我在数组中有一个字节字符串集合。但是,我要做的是分别分析每个字节。.因此,我不想在整个数组上工作,而是一次要处理单个字节字符串,那是该数组的一个组成部分。阵列”。现在在下面的代码中:“字节bv = 10;字符串hexString = Integer.toHexString(bv);” CAse 1(已接收字节:68十六进制输出:: 44)情况:2(已接收字节:-46十六进制输出:: ffffffd2) .........对于某些值,为什么会得到如此意外的结果?
维威克

1
@Vivek:阅读有关使用的答案toHexString。您必须使用掩盖它& 0xFF,即Integer.toHexString(-46 & 0xFF)is "d2"
polygenelubricants 2010年

@polygenelubricants:非常感谢。似乎最终代码可以正常工作。现在使用toHexString函数安全吗?或者,该方法可能存在一些漏洞?
维威克

1
@Vivek:这是“安全的”,您只需要小心并确保每次都掩盖该byte& 0xFF。在format上述方案可能还需要取决于你实际上使用作为参数屏蔽。
polygenelubricants 2010年

65

我之所以发表这样的帖子,是因为现有的答案都无法解释为什么他们的方法有效,我认为这对于解决这个问题确实很重要。在某些情况下,这会使所提出的解决方案显得不必要地复杂而微妙。为了说明这一点,我将提供一种相当简单的方法,但是我将提供更多细节以帮助说明为什么它的工作原理。

首先,我们要做什么?我们想将一个字节值(或字节数组)转换为一个表示ASCII十六进制值的字符串。因此,第一步是确切地找出Java中的字节是什么:

字节数据类型是8位带符号的二进制补码整数。最小值为-128,最大值为127(含)。字节数据类型对于在大数组中节省内存非常有用,因为内存的节省实际上很重要。它们也可以用来代替int,因为它们的限制有助于阐明您的代码;变量范围有限的事实可以作为文档的一种形式。

这是什么意思?一些事情:首先也是最重要的是,这意味着我们正在与 8位。因此,例如,我们可以将数字2写为00000010。但是,由于它是二进制补码,因此我们可以这样写一个负数2:11111110。这也意味着转换为十六进制非常简单。也就是说,您只需将每个4位段直接转换为十六进制。请注意,要在此方案中理解负数,您首先需要了解二进制补码。如果您还不了解二进制补码,可以在这里阅读出色的解释:http : //www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html


一般将Two的补码转换为十六进制

一旦数字为二进制补码,就很难将其转换为十六进制。通常,从二进制转换为十六进制非常简单,如您在下面的两个示例中所见,可以直接从二进制补码转换为十六进制。

例子

范例1:将2转换为十六进制。

1)首先将2转换为二进制补码形式的二进制数:

2 (base 10) = 0000 0010 (base 2)

2)现在将二进制转换为十六进制:

0000 = 0x0 in hex
0010 = 0x2 in hex

therefore 2 = 0000 0010 = 0x02. 

范例2:将-2(以二进制补码)转换为十六进制。

1)首先将-2转换为二进制补码形式的二进制数:

-2 (base 10) = 0000 0010 (direct conversion to binary) 
               1111 1101 (invert bits)
               1111 1110 (add 1)
therefore: -2 = 1111 1110 (in two's complement)

2)现在转换为十六进制:

1111 = 0xF in hex
1110 = 0xE in hex

therefore: -2 = 1111 1110 = 0xFE.


用Java做到这一点

现在我们已经涵盖了概念,您将发现我们可以通过一些简单的遮罩和移动来实现我们想要的。要了解的关键是,您要转换的字节已经是二进制补码。您自己不要进行此转换。我认为这是这个问题上的一个主要困惑点。以以下字节数组为例:

byte[] bytes = new byte[]{-2,2};

上面我们只是将它们手动转换为十六进制,但是如何用Java做到呢?这是如何做:

步骤1:创建一个StringBuffer来保存我们的计算。

StringBuffer buffer = new StringBuffer();

第2步:隔离高阶位,将其转换为十六进制,然后将其附加到缓冲区

给定二进制数1111 1110,我们可以通过以下方式隔离高阶位:首先将它们移位4,然后将其余数字清零。从逻辑上讲这很简单,但是,由于符号扩展,Java(和许多语言)的实现细节引起了争议。本质上,当您移位字节值时,Java首先将您的值转换为整数,然后执行符号扩展。因此,尽管您希望1111 1110 >> 4为0000 1111,但实际上在Java中,它表示为二进制补码0xFFFFFFFF!

所以回到我们的例子:

1111 1110 >> 4 (shift right 4) = 1111 1111 1111 1111 1111 1111 1111 1111 (32 bit sign-extended number in two's complement)

然后,我们可以使用掩码隔离位:

1111 1111 1111 1111 1111 1111 1111 1111 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1111
therefore: 1111 = 0xF in hex. 

在Java中,我们可以一次性完成所有操作:

Character.forDigit((bytes[0] >> 4) & 0xF, 16);

forDigit函数只是将您传递的数字映射到十六进制数字集0-F上。

步骤3:接下来,我们需要隔离低阶位。由于我们想要的位已经在正确的位置,因此我们可以将它们屏蔽掉:

1111 1110 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1110 (recall sign extension from before)
therefore: 1110 = 0xE in hex.  

像以前一样,在Java中,我们可以一次完成所有操作:

Character.forDigit((bytes[0] & 0xF), 16);

将所有这些放在一起,我们可以将其作为for循环并转换整个数组:

for(int i=0; i < bytes.length; i++){
    buffer.append(Character.forDigit((bytes[i] >> 4) & 0xF, 16));
    buffer.append(Character.forDigit((bytes[i] & 0xF), 16));
}

希望这种解释使您更清楚地想知道在Internet上找到的许多示例中发生了什么。希望我没有犯任何严重的错误,但是非常欢迎提出建议和更正!


4
最佳答案!十六进制String到字节的对称实现将进行转换,然后使用Character.digit(),例如(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
ericbn 2014年

21

最快的我还没有发现这样做的方式如下:

private static final String    HEXES    = "0123456789ABCDEF";

static String getHex(byte[] raw) {
    final StringBuilder hex = new StringBuilder(2 * raw.length);
    for (final byte b : raw) {
        hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
    }
    return hex.toString();
}

比快约50倍String.format。如果要测试:

public class MyTest{
    private static final String    HEXES        = "0123456789ABCDEF";

    @Test
    public void test_get_hex() {
        byte[] raw = {
            (byte) 0xd0, (byte) 0x0b, (byte) 0x01, (byte) 0x2a, (byte) 0x63,
            (byte) 0x78, (byte) 0x01, (byte) 0x2e, (byte) 0xe3, (byte) 0x6c,
            (byte) 0xd2, (byte) 0xb0, (byte) 0x78, (byte) 0x51, (byte) 0x73,
            (byte) 0x34, (byte) 0xaf, (byte) 0xbb, (byte) 0xa0, (byte) 0x9f,
            (byte) 0xc3, (byte) 0xa9, (byte) 0x00, (byte) 0x1e, (byte) 0xd5,
            (byte) 0x4b, (byte) 0x89, (byte) 0xa3, (byte) 0x45, (byte) 0x35,
            (byte) 0xd6, (byte) 0x10,
        };

        int N = 77777;
        long t;

        {
            t = System.currentTimeMillis();
            for (int i = 0; i < N; i++) {
                final StringBuilder hex = new StringBuilder(2 * raw.length);
                for (final byte b : raw) {
                    hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
                }
                hex.toString();
            }
            System.out.println(System.currentTimeMillis() - t); // 50
        }

        {
            t = System.currentTimeMillis();
            for (int i = 0; i < N; i++) {
                StringBuilder hex = new StringBuilder(2 * raw.length);
                for (byte b : raw) {
                    hex.append(String.format("%02X", b));
                }
                hex.toString();
            }
            System.out.println(System.currentTimeMillis() - t); // 2535
        }

    }
}

编辑:刚发现的东西速度更快,并且只停留在一条线上,但与JRE 9 不兼容使用后果自负

import javax.xml.bind.DatatypeConverter;

DatatypeConverter.printHexBinary(raw);

2
DatatypeConverter不再用Java 9.危险的事情是使用它的Java 1.8下将代码编译或更早版本(Java 9源设置更早),但Java的9下得到一个运行时异常
斯蒂芬·中号-on透湿

我第二个@StephenMs点:与jre9一起使用时,ClassNotFound异常会导致崩溃
Patrick Favre

实际上可以简单地printHexBinary 从jdk的src.zip中提取源代码方法 ,这似乎比第一种方法快1倍。
水果

1
如果为HEXES常量使用char数组,而不是String和charAt(),则速度提高约20%。
Dyorgio '18

15

尝试这种方式:

byte bv = 10;
String hexString = Integer.toHexString(bv);

处理数组(如果我对您的理解正确):

byte[] bytes = {9, 10, 11, 15, 16};
StringBuffer result = new StringBuffer();
for (byte b : bytes) {
    result.append(String.format("%02X ", b));
    result.append(" "); // delimiter
}
return result.toString();

正如多基因润滑剂所提到的,String.format()与之相对的答案是正确的Integer.toHexString()(因为它以正确的方式处理负数)。


2
这将标志扩展,例如try -1
polygenelubricants 2010年

字节bv = 10; 字符串hexString = Integer.toHexString(bv); 这似乎工作正常。.我可以将其分别应用于数组的每个元素。.其他代码(使用array处理)返回的值太大。原因是什么呢?
维威克

@Vivek,因为bv它返回一个十六进制字符。而其余的代码返回一个十六进制字符串。我已经用分隔符更改了代码,所以您现在可以理解它。
0x2D9A3'5

@Bar:Integer.toHexString如果将bytewith 屏蔽掉0xFF以撤消符号扩展名,仍可以使用。
polygenelubricants 2010年

原因1(已接收字节:68十六进制输出:: 44)情况:2(已接收字节:-46十六进制输出:: ffffffd2)在负字节数组的情况下,我得到了意外的输出值...如何处理呢?
维威克

13

最好的解决方案是这种坏蛋一线:

String hex=DatatypeConverter.printHexBinary(byte[] b);

这里提到的


4
DatatypeConverter不再用Java 9.危险的事情是使用它的Java 1.8下将代码编译或更早版本(Java 9源设置更早),但Java的9下得到一个运行时异常
斯蒂芬·中号-on透湿

当您说它不在jdk9中时,很可悲。new BigInteger(byteArray).toString(16)那是要走的路。是perf问题吗?
祈祷之

也许不是性能问题,但它将错过前导零(因为它们对像BigInteger这样的数字没有意义)
Friso

看起来它仍在Java 9文档中,所以按照我的判断,仍然可以使用它
Brad Parks

我觉得作为解释在这里它仍然是确定用于java9,但会删除在未来的Java版本。从版本2.3.0开始,您仍然可以将其与“新”独立jaxb模块一起使用。

11

如果您想要一个等宽的十六进制表示形式,即0A代替A,以便可以明确地恢复字节,请尝试format()

StringBuilder result = new StringBuilder();
for (byte bb : byteArray) {
    result.append(String.format("%02X", bb));
}
return result.toString();

11

使用以下简短而简单的方式转换byte[]为十六进制字符串BigInteger

import java.math.BigInteger;

byte[] bytes = new byte[] {(byte)255, 10, 20, 30};
String hex = new BigInteger(1, bytes).toString(16);
System.out.println(hex); // ff0a141e

这个怎么运作?

内置系统类java.math.BigInteger类(java.math.BigInteger)与二进制和十六进制数据兼容:

  • 它有一个构造函数BigInteger(signum=1, byte[])来创建一个大整数byte[](通过设置其第一个参数signum= 1以正确处理负字节)
  • 使用BigInteger.toString(16)的大整数转换为十六进制字符串
  • 要解析一个十六进制数字,请使用new BigInteger("ffa74b", 16)-无法正确处理前导零

如果您可能想在十六进制结果中使用前导零,请检查其大小并在必要时添加缺失的零:

if (hex.length() % 2 == 1)
    hex = "0" + hex;

笔记

使用new BigInteger(1, bytes)而不是new BigInteger(bytes),因为Java是“ 被设计破坏 ”的,并且byte数据类型不包含字节而是带符号的小整数[-128 ... 127]。如果第一个字节为负,则BigInteger假定您传递一个负大整数。只需1作为第一个参数(signum=1)传递即可。

从十六进制到byte[]的转换非常棘手:有时在产生的输出中输入前导零,应按以下方式清除它:

byte[] bytes = new BigInteger("ffa74b", 16).toByteArray();
if (bytes[0] == 0) {
    byte[] newBytes = new byte[bytes.length - 1];
    System.arraycopy(bytes, 1, newBytes, 0, newBytes.length);
    bytes = newBytes;
}

最后要注意的是,如果byte[]具有多个前导零,则它们将丢失。


1
如果前导字节的十进制值小于16,您还将得到一个带有奇数个十六进制字符的字符串。
亚历克斯·乔根森

8

如果您乐于使用外部库,则org.apache.commons.codec.binary.Hex该类具有一个encodeHex方法,该方法采用a byte[]并返回a char[]。此方法比format选项快得多,并且封装了转换的详细信息。还带有decodeHex相反转换的方法。


4
一个更简单的方法是使用内置函数javax.xml.bind.DatatypeConverter / parseHexBinary和printHexBinary。见stackoverflow.com/questions/9655181/…–
艾伦·汤普森

2
+1此选项。十六进制还具有一个encodeHexString方法,该方法接受一个byte []并返回一个String。
Mingjiang Shi

不要忘记javax名称空间并非总是可用。
Mene's

7

您可以使用Bouncy Castle Provider库中的方法:

org.bouncycastle.util.encoders.Hex.toHexString(byteArray);

Bouncy Castle Crypto软件包是密码算法的Java实现。该jar包含JCE提供程序和轻量级API,用于JDK 1.5至JDK 1.8的Bouncy Castle密码学API。

Maven依赖项:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.60</version>
</dependency>

或来自Apache Commons Codec

org.apache.commons.codec.binary.Hex.encodeHexString(byteArray);

Apache Commons Codec软件包包含用于各种格式(例如Base64和Hexadecimal)的简单编码器和解码器。除了这些广泛使用的编码器和解码器之外,编解码器包还维护了语音编码实用程序的集合。

Maven依赖项:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.11</version>
</dependency>

是的,这是最好的解决方案,但需要一个外部库:Apache Commons Codecmvnrepository.com/artifact/commons-codec/commons-codec/1.11)或BouncyCastle Providermvnrepository.com/artifact/org.bouncycastle/bcprov- jdk15on / 1.60
Svetlin Nakov

5

这是到目前为止我发现运行最快的代码。我在23ms的长度为32的109015字节数组上运行了它。我在VM上运行它,因此它可能在裸机上运行得更快。

public static final char[] HEX_DIGITS =         {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

public static char[] encodeHex( final byte[] data ){
    final int l = data.length;
    final char[] out = new char[l<<1];
    for( int i=0,j=0; i<l; i++ ){
        out[j++] = HEX_DIGITS[(0xF0 & data[i]) >>> 4];
        out[j++] = HEX_DIGITS[0x0F & data[i]];
    }
    return out;
}

那你就可以做

String s = new String( encodeHex(myByteArray) );

3
BigInteger n = new BigInteger(byteArray);
String hexa = n.toString(16));

不起作用:BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)退货"-fdfcfbfb"
Martin Vysny

这是正确的结果。您使用字节“ -1”,“ 2” ...“ 5”。如果您打算使用字面量'-1','2'...'5',则这些字节没有可视化(unicode.org),您应该使用字符串值。
将于

结果错误。(int) 255由于Java字节已签名,因此Java字节值-1实际上为0xFF(与相同),因此结果应为FF02030405。如果您尝试上面的@Jerinaw解决方案,您会看到它将打印正确的输出。另请参阅下面的Svetlin Nakov解决方案。
Martin Vysny

2

这是将字节转换为十六进制的简单函数

   private static String convertToHex(byte[] data) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < data.length; i++) {
        int halfbyte = (data[i] >>> 4) & 0x0F;
        int two_halfs = 0;
        do {
            if ((0 <= halfbyte) && (halfbyte <= 9))
                buf.append((char) ('0' + halfbyte));
            else
                buf.append((char) ('a' + (halfbyte - 10)));
            halfbyte = data[i] & 0x0F;
        } while(two_halfs++ < 1);
    }
    return buf.toString();
}

2

其他人已经涵盖了一般情况。但是,如果您具有已知格式的字节数组,例如MAC地址,则可以:

byte[] mac = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };

String str = String.format("%02X:%02X:%02X:%02X:%02X:%02X",
                           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 

1

创建(并销毁)一堆 String如果性能是一个问题,那么实例并不是一个好方法。

请忽略那些冗长(重复)的参数检查语句if。这是出于(另一个)教育目的。

完整的Maven项目:http : //jinahya.googlecode.com/svn/trunk/com.googlecode.jinahya/hex-codec/

编码中...

/**
 * Encodes a single nibble.
 *
 * @param decoded the nibble to encode.
 *
 * @return the encoded half octet.
 */
protected static int encodeHalf(final int decoded) {

    switch (decoded) {
        case 0x00:
        case 0x01:
        case 0x02:
        case 0x03:
        case 0x04:
        case 0x05:
        case 0x06:
        case 0x07:
        case 0x08:
        case 0x09:
            return decoded + 0x30; // 0x30('0') - 0x39('9')
        case 0x0A:
        case 0x0B:
        case 0x0C:
        case 0x0D:
        case 0x0E:
        case 0x0F:
            return decoded + 0x57; // 0x41('a') - 0x46('f')
        default:
            throw new IllegalArgumentException("illegal half: " + decoded);
    }
}


/**
 * Encodes a single octet into two nibbles.
 *
 * @param decoded the octet to encode.
 * @param encoded the array to which each encoded nibbles are written.
 * @param offset the offset in the array.
 */
protected static void encodeSingle(final int decoded, final byte[] encoded,
                                   final int offset) {

    if (encoded == null) {
        throw new IllegalArgumentException("null encoded");
    }

    if (encoded.length < 2) {
        // not required
        throw new IllegalArgumentException(
            "encoded.length(" + encoded.length + ") < 2");
    }

    if (offset < 0) {
        throw new IllegalArgumentException("offset(" + offset + ") < 0");
    }

    if (offset >= encoded.length - 1) {
        throw new IllegalArgumentException(
            "offset(" + offset + ") >= encoded.length(" + encoded.length
            + ") - 1");
    }

    encoded[offset] = (byte) encodeHalf((decoded >> 4) & 0x0F);
    encoded[offset + 1] = (byte) encodeHalf(decoded & 0x0F);
}


/**
 * Decodes given sequence of octets into a sequence of nibbles.
 *
 * @param decoded the octets to encode
 *
 * @return the encoded nibbles.
 */
protected static byte[] encodeMultiple(final byte[] decoded) {

    if (decoded == null) {
        throw new IllegalArgumentException("null decoded");
    }

    final byte[] encoded = new byte[decoded.length << 1];

    int offset = 0;
    for (int i = 0; i < decoded.length; i++) {
        encodeSingle(decoded[i], encoded, offset);
        offset += 2;
    }

    return encoded;
}


/**
 * Encodes given sequence of octets into a sequence of nibbles.
 *
 * @param decoded the octets to encode.
 *
 * @return the encoded nibbles.
 */
public byte[] encode(final byte[] decoded) {

    return encodeMultiple(decoded);
}

解码...

/**
 * Decodes a single nibble.
 *
 * @param encoded the nibble to decode.
 *
 * @return the decoded half octet.
 */
protected static int decodeHalf(final int encoded) {

    switch (encoded) {
        case 0x30: // '0'
        case 0x31: // '1'
        case 0x32: // '2'
        case 0x33: // '3'
        case 0x34: // '4'
        case 0x35: // '5'
        case 0x36: // '6'
        case 0x37: // '7'
        case 0x38: // '8'
        case 0x39: // '9'
            return encoded - 0x30;
        case 0x41: // 'A'
        case 0x42: // 'B'
        case 0x43: // 'C'
        case 0x44: // 'D'
        case 0x45: // 'E'
        case 0x46: // 'F'
            return encoded - 0x37;
        case 0x61: // 'a'
        case 0x62: // 'b'
        case 0x63: // 'c'
        case 0x64: // 'd'
        case 0x65: // 'e'
        case 0x66: // 'f'
            return encoded - 0x57;
        default:
            throw new IllegalArgumentException("illegal half: " + encoded);
    }
}


/**
 * Decodes two nibbles into a single octet.
 *
 * @param encoded the nibble array.
 * @param offset the offset in the array.
 *
 * @return decoded octet.
 */
protected static int decodeSingle(final byte[] encoded, final int offset) {

    if (encoded == null) {
        throw new IllegalArgumentException("null encoded");
    }

    if (encoded.length < 2) {
        // not required
        throw new IllegalArgumentException(
            "encoded.length(" + encoded.length + ") < 2");
    }

    if (offset < 0) {
        throw new IllegalArgumentException("offset(" + offset + ") < 0");
    }

    if (offset >= encoded.length - 1) {
        throw new IllegalArgumentException(
            "offset(" + offset + ") >= encoded.length(" + encoded.length
            + ") - 1");
    }

    return (decodeHalf(encoded[offset]) << 4)
           | decodeHalf(encoded[offset + 1]);
}


/**
 * Encodes given sequence of nibbles into a sequence of octets.
 *
 * @param encoded the nibbles to decode.
 *
 * @return the encoded octets.
 */
protected static byte[] decodeMultiple(final byte[] encoded) {

    if (encoded == null) {
        throw new IllegalArgumentException("null encoded");
    }

    if ((encoded.length & 0x01) == 0x01) {
        throw new IllegalArgumentException(
            "encoded.length(" + encoded.length + ") is not even");
    }

    final byte[] decoded = new byte[encoded.length >> 1];

    int offset = 0;
    for (int i = 0; i < decoded.length; i++) {
        decoded[i] = (byte) decodeSingle(encoded, offset);
        offset += 2;
    }

    return decoded;
}


/**
 * Decodes given sequence of nibbles into a sequence of octets.
 *
 * @param encoded the nibbles to decode.
 *
 * @return the decoded octets.
 */
public byte[] decode(final byte[] encoded) {

    return decodeMultiple(encoded);
}

1

这是一种非常快速的方法。无需外部库。

final protected static char[] HEXARRAY = "0123456789abcdef".toCharArray();

    public static String encodeHexString( byte[] bytes ) {

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

1

我无法弄清楚字节字符串到底是什么意思,但是这里有一些从字节到字符串的转换,反之亦然,当然,官方文档还有很多

Integer intValue = 149;

相应的字节值为:

Byte byteValue = intValue.byteValue(); // this will convert the rightmost byte of the intValue to byte, because Byte is an 8 bit object and Integer is at least 16 bit, and it will give you a signed number in this case -107

从Byte变量获取整数值:

Integer anInt = byteValue.intValue(); // This will convert the byteValue variable to a signed Integer

从字节和整数到十六进制字符串:
这是我的方法:

Integer anInt = 149
Byte aByte = anInt.byteValue();

String hexFromInt = "".format("0x%x", anInt); // This will output 0x95
String hexFromByte = "".format("0x%x", aByte); // This will output 0x95

将字节数组转换为十六进制字符串:
据我所知,没有简单的函数可以将某些数组中的所有元素转换Object为另一个元素Object,因此您必须自己做。您可以使用以下功能:

从byte []到String:

    public static String byteArrayToHexString(byte[] byteArray){
        String hexString = "";

        for(int i = 0; i < byteArray.length; i++){
            String thisByte = "".format("%x", byteArray[i]);
            hexString += thisByte;
        }

        return hexString;
    }

从十六进制字符串到字节[]:

public static byte[] hexStringToByteArray(String hexString){
    byte[] bytes = new byte[hexString.length() / 2];

    for(int i = 0; i < hexString.length(); i += 2){
        String sub = hexString.substring(i, i + 2);
        Integer intVal = Integer.parseInt(sub, 16);
        bytes[i / 2] = intVal.byteValue();
        String hex = "".format("0x%x", bytes[i / 2]);
    }

    return bytes;
}  

为时已晚,但我希望这可以对其他人有所帮助;)


1

有您的快速方法:

    private static final String[] hexes = new String[]{
        "00","01","02","03","04","05","06","07","08","09","0A","0B","0C","0D","0E","0F",
        "10","11","12","13","14","15","16","17","18","19","1A","1B","1C","1D","1E","1F",
        "20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F",
        "30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F",
        "40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F",
        "50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F",
        "60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F",
        "70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F",
        "80","81","82","83","84","85","86","87","88","89","8A","8B","8C","8D","8E","8F",
        "90","91","92","93","94","95","96","97","98","99","9A","9B","9C","9D","9E","9F",
        "A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","AA","AB","AC","AD","AE","AF",
        "B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF",
        "C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB","CC","CD","CE","CF",
        "D0","D1","D2","D3","D4","D5","D6","D7","D8","D9","DA","DB","DC","DD","DE","DF",
        "E0","E1","E2","E3","E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF",
        "F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF"
    };

    public static String byteToHex(byte b) {
        return hexes[b&0xFF];
    }

1
难看,但可能非常有效。:-)
Rich S

1

就像其他答案一样,我建议使用String.format()BigInteger。但是要将字节数组解释为大端二进制表示,而不是二进制补码二进制表示(具有可能的十六进制值范围的符号和不完整使用),请使用BigInteger(int signum,byte [] itude)而不是BigInteger(byte [] val )

例如,对于长度为8的字节数组,请使用:

String.format("%016X", new BigInteger(1,bytes))

优点:

  • 前导零
  • 没有信号
  • 仅内置功能
  • 只有一行代码

坏处:

  • 可能会有更有效的方法

例:

byte[] bytes = new byte[8];
Random r = new Random();
System.out.println("big-endian       | two's-complement");
System.out.println("-----------------|-----------------");
for (int i = 0; i < 10; i++) {
    r.nextBytes(bytes);
    System.out.print(String.format("%016X", new BigInteger(1,bytes)));
    System.out.print(" | ");
    System.out.print(String.format("%016X", new BigInteger(bytes)));
    System.out.println();
}

输出示例:

big-endian       | two's-complement
-----------------|-----------------
3971B56BC7C80590 | 3971B56BC7C80590
64D3C133C86CCBDC | 64D3C133C86CCBDC
B232EFD5BC40FA61 | -4DCD102A43BF059F
CD350CC7DF7C9731 | -32CAF338208368CF
82CDC9ECC1BC8EED | -7D3236133E437113
F438C8C34911A7F5 | -BC7373CB6EE580B
5E99738BE6ACE798 | 5E99738BE6ACE798
A565FE5CE43AA8DD | -5A9A01A31BC55723
032EBA783D2E9A9F | 032EBA783D2E9A9F
8FDAA07263217ABA | -70255F8D9CDE8546

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.