在Java中,如何将字节数组转换为十六进制字符串并保留前导零?

171

我正在使用一些用于生成MD5哈希的Java示例代码。其中一部分将结果从字节转换为十六进制数字字符串:

byte messageDigest[] = algorithm.digest();     
StringBuffer hexString = new StringBuffer();
for (int i=0;i<messageDigest.length;i++) {
    hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
    }

然而,这种方法并不完全有效,因为 toHexString 显然会删除前导零。那么,从字节数组转换为十六进制字符串并保留前导零的最简单方法是什么?

28个回答

6
String result = String.format("%0" + messageDigest.length + "s", hexString.toString())

根据您已有的内容,这是最简短的解决方案。如果您可以将字节数组转换为数字值,String.format 可以同时将其转换为十六进制字符串。


非常优雅,除了需要Java 1.5+。虽然现在已经不是问题了... - Fernando Miguélez
3
无法工作: 线程中出现异常:“main” java.util.FormatFlagsConversionMismatchException: Conversion = s,Flags = 0。 - Noah Yetter

5

另一个选项

public static String toHexString(byte[]bytes) {
    StringBuilder sb = new StringBuilder(bytes.length*2);
    for(byte b: bytes)
      sb.append(Integer.toHexString(b+0x800).substring(1));
    return sb.toString();
}

5
这个方案有点老派,但应该能更节约内存。
public static String toHexString(byte bytes[]) {
    if (bytes == null) {
        return null;
    }

    StringBuffer sb = new StringBuffer();
    for (int iter = 0; iter < bytes.length; iter++) {
        byte high = (byte) ( (bytes[iter] & 0xf0) >> 4);
        byte low =  (byte)   (bytes[iter] & 0x0f);
        sb.append(nibble2char(high));
        sb.append(nibble2char(low));
    }

    return sb.toString();
}

private static char nibble2char(byte b) {
    byte nibble = (byte) (b & 0x0f);
    if (nibble < 10) {
        return (char) ('0' + nibble);
    }
    return (char) ('a' + nibble - 10);
}

4
为了保留前导零,这里有一个小变化,基于Paul的建议(例如md5哈希):

为了保留前导零,这里有一个小变化,基于Paul的建议(例如md5哈希):

public static String MD5hash(String text) throws NoSuchAlgorithmException {
    byte[] hash = MessageDigest.getInstance("MD5").digest(text.getBytes());
    return String.format("%032x",new BigInteger(1, hash));
}

抱歉,这看起来比Ayman提出的要差,很抱歉。


4
static String toHex(byte[] digest) {
    String digits = "0123456789abcdef";
    StringBuilder sb = new StringBuilder(digest.length * 2);
    for (byte b : digest) {
        int bi = b & 0xff;
        sb.append(digits.charAt(bi >> 4));
        sb.append(digits.charAt(bi & 0xf));
    }
    return sb.toString();
}

我非常想看看这与Jemenake的解决方案相比如何。 - Anm

3

看起来,连接(concat)和附加(append)函数可能非常慢。以下方法对我来说比之前的帖子快得多。 在构建输出时改用字符数组是加速的关键因素。 我还没有与Brandon DuRette建议的Hex.encodeHex进行比较。

public static String toHexString(byte[] bytes) {
    char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    char[] hexChars = new char[10000000];
    int c = 0;
    int v;
    for ( j = 0; j < bytes.length; j++ ) {
        v = bytes[j] & 0xFF;
        hexChars[c] = hexArray[v/16];
        c++;
        hexChars[c] = hexArray[v%16];
        c++;
    }
    return new String(hexChars, 0, c); }

那个两兆字节的分配 (= new char[10000000];) 完全是不必要和浪费的。 - Anm
二十兆字节,哈哈。虽然 bytes.length * 4 字节就足够了。 - Robert

2

这是我用于MD5哈希的工具:

public static String getMD5(String filename)
        throws NoSuchAlgorithmException, IOException {
    MessageDigest messageDigest = 
        java.security.MessageDigest.getInstance("MD5");

    InputStream in = new FileInputStream(filename);

    byte [] buffer = new byte[8192];
    int len = in.read(buffer, 0, buffer.length);

    while (len > 0) {
        messageDigest.update(buffer, 0, len);
        len = in.read(buffer, 0, buffer.length);
    }
    in.close();

    return new BigInteger(1, messageDigest.digest()).toString(16);
}

编辑:我已经测试过,发现这个方法也会删去尾随的零。但是这种情况只会在开头发生,所以您可以与预期长度进行比较并相应地填充。


2

您可以不使用外部库来减少编写量:

String hex = (new HexBinaryAdapter()).marshal(md5.digest(YOUR_STRING.getBytes()))

2
这个解决方案不需要进行位移或掩码、查找表或外部库,而且已经是我能得到的最短的方案了。
byte[] digest = new byte[16];       

Formatter fmt = new Formatter();    
for (byte b : digest) { 
  fmt.format("%02X", b);    
}

fmt.toString()

1
byte messageDigest[] = algorithm.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
    String hexByte = Integer.toHexString(0xFF & messageDigest[i]);
    int numDigits = 2 - hexByte.length();
    while (numDigits-- > 0) {
        hexString.append('0');
    }
    hexString.append(hexByte);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接