【问题标题】:Is this the best way to convert String hex to bytes?这是将字符串十六进制转换为字节的最佳方法吗?
【发布时间】:2023-03-24 09:53:02
【问题描述】:

这是将十六进制字符串转换为字节的最佳方法吗? 或者你能想一个更短/更简单的吗?

public static byte[] hexToBytes(String hex) {
return hexToBytes(hex.toCharArray());
}

public static byte[] hexToBytes(char[] hex) {
int length = hex.length / 2;
byte[] raw = new byte[length];
for (int i = 0; i < length; i++) {
    int high = Character.digit(hex[i * 2], 16);
    int low = Character.digit(hex[i * 2 + 1], 16);
    int value = (high << 4) | low;
    if (value > 127)
    value -= 256;
    raw[i] = (byte) value;
}
return raw;
}

【问题讨论】:

  • @Tom Brito:你有什么要求?在我的书中,“3ED”是一个完全有效的“hexstring”,但你的程序不能处理这样的字符串。 “0x3ED”呢? (您的程序在后一种情况下也不起作用)。
  • @WizardOfOdds 实际上,它不是我的 java2s.com/Code/Java/Development-Class/ConverthexToBytes.htm>。但是,在我的应用程序中,您的十六进制值将生成为“0x03ED”(十六进制值始终生成,从不直接输入)。无论如何,谢谢你记住这一点。

标签: java bytearray hex


【解决方案1】:
byte[] yourBytes = new BigInteger(hexString, 16).toByteArray();

【讨论】:

  • 支持的最大 hexString 长度是多少?
  • BitInteger 处理任意精度的整数,因此它应该是任意大小。
  • 这并不总是像您预期的那样工作。例如:"0001" 变成一个字节,而合理地期望它变成两个。
  • Drew 的警告非常重要。这不是一般十六进制解码的安全方法。
【解决方案2】:

当值大于 127 时,不需要减去 256。只需将值转换为字节即可。例如,byte b = (byte) 255 将值 -1 分配给 b

整数类型的窄化转换只是丢弃不适合目标类型的高位。

  private static byte[] hexToBytes(char[] hex)
  {
    byte[] raw = new byte[hex.length / 2];
    for (int src = 0, dst = 0; dst < raw.length; ++dst) {
      int hi = Character.digit(hex[src++], 16);
      int lo = Character.digit(hex[src++], 16);
      if ((hi < 0) || (lo < 0))
        throw new IllegalArgumentException();
      raw[dst] = (byte) (hi << 4 | lo);
    }
    return raw;
  }

【讨论】:

    【解决方案3】:

    很遗憾,当有前导零字节时,使用 BigInteger 会失败。

    我认为您最初的方法是一个好的开始。我做了一些调整:

    @NotNull
    public static byte[] hexToBytes(@NotNull String hex)
    {
        return hexToBytes(hex.toCharArray());
    }
    
    @NotNull
    public static byte[] hexToBytes(@NotNull char[] hex)
    {
        if (hex.length % 2 != 0)
            throw new IllegalArgumentException("Must pass an even number of characters.");
    
        int length = hex.length >> 1;
        byte[] raw = new byte[length];
        for (int o = 0, i = 0; o < length; o++) {
            raw[o] = (byte) ((getHexCharValue(hex[i++]) << 4)
                            | getHexCharValue(hex[i++]));
        }
        return raw;
    }
    
    public static byte getHexCharValue(char c)
    {
        if (c >= '0' && c <= '9')
            return (byte) (c - '0');
        if (c >= 'A' && c <= 'F')
            return (byte) (10 + c - 'A');
        if (c >= 'a' && c <= 'f')
            return (byte) (10 + c - 'a');
        throw new IllegalArgumentException("Invalid hex character");
    }
    

    请注意,Character.digit 仅在 Java 7 中可用,它不会验证提供的字符是否在预期范围内。当输入数据不符合我的期望时,我喜欢抛出异常,所以我添加了它。

    以下是一些基本的单元测试:

    @Test
    public void hexToBytes()
    {
        assertArrayEquals(new byte[]{0x00, 0x01, 0x02}, Convert.hexToBytes("000102"));
        assertArrayEquals(new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0xFD}, Convert.hexToBytes("FFFEFD"));
        assertArrayEquals(new byte[]{(byte) 0xFF}, Convert.hexToBytes("FF"));
        assertArrayEquals(new byte[]{(byte) 0x00}, Convert.hexToBytes("00"));
        assertArrayEquals(new byte[]{(byte) 0x01}, Convert.hexToBytes("01"));
        assertArrayEquals(new byte[]{(byte) 0x7F}, Convert.hexToBytes("7F"));
        assertArrayEquals(new byte[]{(byte) 0x80}, Convert.hexToBytes("80"));
    }
    
    @Test(expected = IllegalArgumentException.class)
    public void hexToBytesThrowsIfOddNumberOfCharacters()
    {
        Convert.hexToBytes("12345"); // Odd number of characters
    }
    
    @Test(expected = IllegalArgumentException.class)
    public void hexToBytesThrowsIfInvalidCharacters()
    {
        Convert.hexToBytes("ABCDEFGH"); // G and H are invalid in base 16
    }
    
    @Test
    public void getHexCharValue()
    {
        assertEquals(0x0, Convert.getHexCharValue('0'));
        assertEquals(0x1, Convert.getHexCharValue('1'));
        assertEquals(0x9, Convert.getHexCharValue('9'));
        assertEquals(0xa, Convert.getHexCharValue('A'));
        assertEquals(0xf, Convert.getHexCharValue('F'));
        assertEquals(0xa, Convert.getHexCharValue('a'));
        assertEquals(0xf, Convert.getHexCharValue('f'));
    }
    
    @Test(expected = IllegalArgumentException.class)
    public void getHexCharValueThrowsIfInvalid1()
    {
        Convert.getHexCharValue('z');
    }
    

    【讨论】:

      【解决方案4】:

      您可以使用Bouncy Castle Crypto 包 - 加密算法的 Java 和 C# 实现。

      // import org.bouncycastle.util.encoders.Hex;
      String msgHex = Hex.toHexString("Ehlo-HEX!".getBytes());
      byte[] msgBytes = Hex.decode(msgHex);
      System.out.println("hex(" + new String(msgBytes) + ")=" + msgHex);
      

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

      【讨论】:

        【解决方案5】:

        最简单的方法:

        private static byte[] hexToBytes(char[] hex)
        {
            return DatatypeConverter.parseHexBinary(hex.toString());
        }
        

        【讨论】:

        • 没有前导零...使用 BigInteger...您会得到尾随零,这可能是个大问题。
        猜你喜欢
        • 1970-01-01
        • 2011-04-06
        • 2023-03-07
        • 2022-06-18
        • 2017-08-23
        • 1970-01-01
        • 2011-10-24
        • 1970-01-01
        • 2019-07-27
        相关资源
        最近更新 更多