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

Eug*_*e M 159 java hex md5

我正在使用一些示例java代码来制作md5哈希.一部分将结果从字节转换为十六进制数字的字符串:

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

但是,由于toHexString显然会从前导零中掉落,所以它并不常用.那么,从字节数组到保持前导零的十六进制字符串的最简单方法是什么?

Bra*_*tte 128

查看Apache Commons Codec Hex.encodeHex.返回类型__CODE__,可以简单地转换为__CODE__.所以:

import org.apache.commons.codec.binary.Hex;

String hex = Hex.encodeHexString(bytes);
Run Code Online (Sandbox Code Playgroud)

  • 只要您使用Apache Commons Codec执行md5,请查看[DigestUtils.md5Hex()](http://commons.apache.org/codec/apidocs/org/apache/commons/codec/digest/ DigestUtils.html#md5Hex(字节[])) (10认同)

Aym*_*man 109

你可以使用下面的那个.我用前导零字节和初始负字节测试了这个

public static String toHex(byte[] bytes) {
    BigInteger bi = new BigInteger(1, bytes);
    return String.format("%0" + (bytes.length << 1) + "X", bi);
}
Run Code Online (Sandbox Code Playgroud)

如果需要小写十六进制数字,请使用"x"String格式.

  • 没有外部依赖,好又短.另外,如果您知道有16个字节/ 32个十六进制数字,那么您的解决方案就会简化为一个简单的单行程序.凉! (3认同)
  • 很好的解决方案!谢谢 (2认同)

Mic*_*ers 101

一种简单的方法是检查输出的位数,Integer.toHexString()并在需要时为每个字节添加前导零.像这样的东西:

public static String toHexString(byte[] bytes) {
    StringBuilder hexString = new StringBuilder();

    for (int i = 0; i < bytes.length; i++) {
        String hex = Integer.toHexString(0xFF & bytes[i]);
        if (hex.length() == 1) {
            hexString.append('0');
        }
        hexString.append(hex);
    }

    return hexString.toString();
}
Run Code Online (Sandbox Code Playgroud)

  • 不,在十六进制值之前,0会附加到`hexString`. (4认同)

小智 38

使用javax.xml.bind.DatatypeConverter.printHexBinary().您可以在http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/DatatypeConverter.html中阅读其文档.

例如:

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

将导致:

000086003D
Run Code Online (Sandbox Code Playgroud)

  • 请记住,从Java 11开始,“ java.xml”包不再是JDK的一部分。 (2认同)

Jem*_*ake 33

我喜欢Steve的提交,但他可以在没有几个变量的情况下完成并在此过程中保存了几行.

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[bytes.length * 2];
    int v;
    for ( int j = 0; j < bytes.length; j++ ) {
        v = bytes[j] & 0xFF;
        hexChars[j*2] = hexArray[v/16];
        hexChars[j*2 + 1] = hexArray[v%16];
    }
    return new String(hexChars);
}
Run Code Online (Sandbox Code Playgroud)

我喜欢这个是很容易看到它正在做什么(而不是依靠一些神奇的BigInteger黑盒转换),你也可以免于担心像前导零和东西这样的角落情况.此例程采用每个4位半字节并将其转换为十六进制字符.它使用表查找,所以它可能很快.如果用逐位移位和AND替换v/16和v%16可能会更快,但我现在懒得测试它.

  • 反函数,也许有人需要它.public static byte [] bytesFromHex(String hexString){final char [] hexArray = {'0','1','2','3','4','5','6','7', '8','9','A','B','C','D','E','F'}; char [] hexChars = hexString.toCharArray(); byte [] result = new byte [hexChars.length/2]; for(int j = 0; j <hexChars.length; j + = 2){result [j/2] =(byte)(Arrays.binarySearch(hexArray,hexChars [j])*16 + Arrays.binarySearch(hexArray, hexChars [j + 1])); 返回结果; } (5认同)

小智 22

我发现Integer.toHexString有点慢.如果要转换许多字节,可能需要考虑构建包含"00"..."FF"的字符串数组,并使用整数作为索引.即

hexString.append(hexArray[0xFF & messageDigest[i]]);
Run Code Online (Sandbox Code Playgroud)

这样更快并确保正确的长度.只需要字符串数组:

String[] hexArray = {
"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"};
Run Code Online (Sandbox Code Playgroud)


小智 12

我一直在寻找同样的东西......这里有一些好主意,但我运行了几个微基准测试.我发现以下是最快的(从Ayman以上修改过来,速度提高约2倍,比Steve高出约50%):

public static String hash(String text, String algorithm)
        throws NoSuchAlgorithmException {
    byte[] hash = MessageDigest.getInstance(algorithm).digest(text.getBytes());
    return new BigInteger(1, hash).toString(16);
}
Run Code Online (Sandbox Code Playgroud)

编辑:哎呀 - 错过了这与kgiannakakis的基本相同,因此可能会删除前导0.但是,将其修改为以下内容,它仍然是最快的:

public static String hash(String text, String algorithm)
        throws NoSuchAlgorithmException {
    byte[] hash = MessageDigest.getInstance(algorithm).digest(text.getBytes());
    BigInteger bi = new BigInteger(1, hash);
    String result = bi.toString(16);
    if (result.length() % 2 != 0) {
        return "0" + result;
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

  • 这仍然是不对的.例如,如果散列是"{0,0,0,0}",那么`BigInteger`的`toString`将只给出"0".这段代码预先添加另一个"0"`并返回"00"`,但结果应为"00000000". (4认同)

Ill*_*huk 11

static String toHex(byte[] digest) {
    StringBuilder sb = new StringBuilder();
    for (byte b : digest) {
        sb.append(String.format("%1$02X", b));
    }

    return sb.toString();
}
Run Code Online (Sandbox Code Playgroud)

  • `StringBuilder`的默认初始容量是16个字符.MD5哈希由32个字符组成.在追加前16个字符之后,内部数组将被复制到长度为34的新数组.此外,`String.format`为摘要的每个字节创建一个新的`Formatter`实例.默认情况下,每个`Formatter`实例化一个新的`StringBuilder`来缓冲其输出.我甚至认为使用32个字符符号初始容量的`StringBuffer`创建一个`Formatter`更容易(`new Formatter(new StringBuilder(32))`)并使用它的`format`和`toString`方法. (3认同)

Ed *_*rty 6

String result = String.format("%0" + messageDigest.length + "s", hexString.toString())
Run Code Online (Sandbox Code Playgroud)

鉴于您已经拥有的东西,这是最短的解决方案.如果您可以将字节数组转换为数字值,String.format可以同时将其转换为十六进制字符串.

  • 不起作用:线程"main"中的异常java.util.FormatFlagsConversionMismatchException:Conversion = s,Flags = 0 (3认同)

kic*_*hik 6

番石榴也很简单:

BaseEncoding.base16().encode( bytes );
Run Code Online (Sandbox Code Playgroud)

当Apache Commons不可用时,这是一个不错的选择。它还具有一些不错的输出控件,例如:

byte[] bytes = new byte[] { 0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
BaseEncoding.base16().lowerCase().withSeparator( ":", 2 ).encode( bytes );
// "0a:0b:0c:0d:0e:0f"
Run Code Online (Sandbox Code Playgroud)


Usa*_*oto 6

我会使用这样的东西来固定长度,比如哈希:

md5sum = String.format("%032x", new BigInteger(1, md.digest()));
Run Code Online (Sandbox Code Playgroud)

0在面具做填充...


小智 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);
}
Run Code Online (Sandbox Code Playgroud)


Pet*_*rey 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();
}
Run Code Online (Sandbox Code Playgroud)