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

时间:2022-10-30 15:50:18

I'm working with some example java code for making md5 hashes. One part converts the results from bytes to a string of hex digits:

我正在使用一些示例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]));
    }

However, it doesn't quite work since toHexString apparently drops off leading zeros. So, what's the simplest way to go from byte array to hex string that maintains the leading zeros?

然而,由于toHexString明显地掉下了前导零,所以它并不十分有效。那么,从字节数组到hex字符串的最简单的方法是什么呢?

27 个解决方案

#1


92  

A simple approach would be to check how many digits are output by Integer.toHexString() and add a leading zero to each byte if needed. Something like this:

一个简单的方法是检查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();
}

#2


123  

Check out Apache Commons Codec Hex.encodeHex. The return type is char[], which can trivially be converted to String. So:

查看Apache Commons Codec Hex.encodeHex。返回类型为char[],可以将其转换为字符串。所以:

  String hexString = new String(Hex.encodeHex(messageDigest));

#3


102  

You can use the one below. I tested this with leading zero bytes and with initial negative bytes as well

你可以用下面这个。我用前导零字节和初始的负字节进行了测试。

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

If you want lowercase hex digits, use "x" in the format String.

如果您想要小写十六进制数字,请在格式字符串中使用“x”。

#4


35  

Use DatatypeConverter.printHexBinary(). You can read its documentation in http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/DatatypeConverter.html

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

For example:

例如:

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

Will result in:

将导致:

000086003D

#5


29  

I liked Steve's submissions, but he could have done without a couple of variables and saved several lines in the process.

我喜欢史蒂夫的建议,但他可以不用几个变量就能完成,并且在这个过程中节省了几行代码。

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);
}

What I like about this is that it's easy to see exactly what it's doing (instead of relying on some magic BigInteger black box conversion) and you're also free from having to worry about corner cases like leading-zeroes and stuff. This routine takes every 4-bit nibble and turns it into a hex char. And it's using a table lookup, so it's probably fast. It could probably be faster if you replace v/16 and v%16 with bitwise shifts and AND's, but I'm too lazy to test it right now.

我喜欢的是,很容易看到它正在做的事情(而不是依赖于一些神奇的BigInteger黑盒转换),而且您也不必担心像“导入-零”之类的角落案例。这个例程每4位咬一次,并把它变成一个十六进制字符。它使用的是表格查找,所以它可能是快速的。如果用位移位代替v/16和v%16,可能会更快,但我现在懒得去测试它。

#6


20  

I found Integer.toHexString to be a little slow. If you are converting many bytes, you may want to consider building an array of Strings containing "00".."FF" and use the integer as the index. I.e.

我发现整数。toHexString有点慢。如果您正在转换许多字节,您可能需要考虑构建包含“00”的字符串数组。使用整数作为索引。即。

hexString.append(hexArray[0xFF & messageDigest[i]]);

This is faster and ensures the correct length. Just requires the array of strings:

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

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"};

#7


12  

I've been looking for the same thing ... some good ideas here, but I ran a few micro benchmarks. I found the following to be the fastest (modified from Ayman's above and about 2x as fast, and about 50% faster than Steve's just above this one):

我一直在找同样的东西…这里有一些不错的想法,但我做了一些微观的基准测试。我发现以下是最快的(从Ayman的上面和大约2x修改得最快,比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);
}

Edit: Oops - missed that this is essentially the same as kgiannakakis's and so may strip off a leading 0. Still, modifying this to the following, it's still the fastest:

编辑:哦,错过了,这基本上和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;
}

#8


11  

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

    return sb.toString();
}

#9


6  

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

That's the shortest solution given what you already have. If you could convert the byte array to a numeric value, String.format can convert it to a hex string at the same time.

这是已知的最短解。如果可以将字节数组转换为数值,字符串。格式可以同时将其转换为十六进制字符串。

#10


5  

This solution is a little older school, and should be memory efficient.

这个解决方案是一个稍微老一点的学校,应该是内存效率。

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);
}

#11


5  

Another option

另一个选择

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();
}

#12


4  

In order to keep leading zeroes, here is a small variation on what has Paul suggested (eg md5 hash):

为了保持领先的零,这里有一个小的变化,保罗建议(如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));
}

Oops, this looks poorer than what's Ayman proposed, sorry for that

哎呀,这看起来比Ayman提出的要穷,抱歉。

#13


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();
}

#14


3  

It appears concat and append functions can be really slow. The following was MUCH faster for me (than my previous post). Changing to a char array in building the output was the key factor to speed it up. I have not compared to Hex.encodeHex suggested by Brandon DuRette.

看起来concat和append函数可以非常慢。下面的内容比我之前的文章要快得多。在构建输出时更改为char数组是加速其速度的关键因素。我没有和海克斯相比。由Brandon DuRette建议的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); }

#15


3  

Guava makes it pretty simple too:

番石榴也很简单:

BaseEncoding.base16().encode( bytes );

It's a nice alternative when Apache Commons is not available. It also has some nice controls of the output like:

当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"

#16


3  

I would use something like this for fixed length, like hashes:

我会用像这样的固定长度,比如哈希:

md5sum = String.format("%032x", new BigInteger(1, md.digest()));

The 0 in the mask does the padding...

掩码中的0做填充…

#17


2  

This what I am using for MD5 hashes:

这就是我使用的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);
}

EDIT: I've tested and I've noticed that with this also trailing zeros are cut. But this can only happen in the beginning, so you can compare with the expected length and pad accordingly.

编辑:我已经测试过了,而且我注意到,在这个后面还有一个0。但这只能在开始时发生,所以你可以与预期的长度和衬垫进行比较。

#18


2  

You can get it writing less without external libraries:

如果没有外部的库,可以少写一些:

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

#19


2  

This solution requires no bit-shifting or -masking, lookup tables, or external libraries, and is about as short as I can get:

这个解决方案不需要位移位或-屏蔽、查找表或外部库,并且是尽可能短的:

byte[] digest = new byte[16];       

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

fmt.toString()

#20


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);
}

#21


0  

IMHO all the solutions above that provide snippets to remove the leading zeroes are wrong.

IMHO上面的所有解决方案都提供了删除前导零的代码片段。

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

According to this snippet, 8 bits are taken from the byte array in an iteration, converted into an integer (since Integer.toHexString function takes int as argument) and then that integer is converted to the corresponding hash value. So, for example if you have 00000001 00000001 in binary, according to the code, the hexString variable would have 0x11 as the hex value whereas correct value should be 0x0101. Thus, while calculating MD5 we may get hashes of length <32 bytes(because of missing zeroes) which may not satisfy the cryptographically unique properties that MD5 hash does.

根据这段代码,在迭代中从字节数组中提取8位,转换为整数(因为整数。toHexString函数将int作为参数,然后将该整数转换为相应的散列值。例如,如果在二进制中有00000001 00000001,根据代码,hexString变量将有0x11作为十六进制值,而正确的值应该是0x0101。因此,在计算MD5时,我们可能会得到长度<32字节的散列(因为丢失的零),这可能无法满足MD5哈希所具有的加密特性。

The solution to the problem is replacing the above code snippet by the following snippet:

问题的解决方案是将上面的代码片段替换为以下代码片段:

byte messageDigest[] = algorithm.digest();
for (int i = 0; i < messageDigest.length; i++) {
    int temp=0xFF & messageDigest[i];
    String s=Integer.toHexString(temp);
    if(temp<=0x0F){
        s="0"+s;
    }
    hexString.append(s);
}

#22


0  

This is also equivalent but more concise using Apache util HexBin where the code reduces to

这也是等效的,但更简洁的是,使用Apache util HexBin,代码可以减少到。

HexBin.encode(messageDigest).toLowerCase();

#23


0  

This will give two-char long string for a byte.

这将为一个字节提供两字符长的字符串。

public String toString(byte b){
    final char[] Hex = new String("0123456789ABCDEF").toCharArray();
    return  "0x"+ Hex[(b & 0xF0) >> 4]+ Hex[(b & 0x0F)];
}

#24


0  

And how can you convert back again from ascii to byte array ?

怎样才能从ascii转换为字节数组呢?

i followed following code to convert to ascii given by Jemenake.

我遵循以下代码转换为Jemenake所提供的ascii。

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);
}

#25


0  

my variant

我的变体

    StringBuilder builder = new StringBuilder();
    for (byte b : bytes)
    {
        builder.append(Character.forDigit(b/16, 16));
        builder.append(Character.forDigit(b % 16, 16));
    }
    System.out.println(builder.toString());

it works for me.

它适合我。

#26


0  

Is that a faulty solution? (android java)

这是一个错误的解决方案吗?(安卓java)

    // Create MD5 Hash
    MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
    digest.update(s.getBytes());
    byte[] md5sum = digest.digest();
    BigInteger bigInt = new BigInteger(1, md5sum);
    String stringMD5 = bigInt.toString(16);
    // Fill to 32 chars
    stringMD5 = String.format("%32s", stringMD5).replace(' ', '0');
    return stringMD5;

So basically it replaces spaces with 0.

所以基本上用0代替空格。

#27


0  

I'm surprised that no one came up with the following solution:

我很惊讶没有人想到下面的解决方案:

StringWriter sw = new StringWriter();
com.sun.corba.se.impl.orbutil.HexOutputStream hex = new com.sun.corba.se.impl.orbutil.HexOutputStream(sw);
hex.write(byteArray);
System.out.println(sw.toString());

#1


92  

A simple approach would be to check how many digits are output by Integer.toHexString() and add a leading zero to each byte if needed. Something like this:

一个简单的方法是检查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();
}

#2


123  

Check out Apache Commons Codec Hex.encodeHex. The return type is char[], which can trivially be converted to String. So:

查看Apache Commons Codec Hex.encodeHex。返回类型为char[],可以将其转换为字符串。所以:

  String hexString = new String(Hex.encodeHex(messageDigest));

#3


102  

You can use the one below. I tested this with leading zero bytes and with initial negative bytes as well

你可以用下面这个。我用前导零字节和初始的负字节进行了测试。

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

If you want lowercase hex digits, use "x" in the format String.

如果您想要小写十六进制数字,请在格式字符串中使用“x”。

#4


35  

Use DatatypeConverter.printHexBinary(). You can read its documentation in http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/DatatypeConverter.html

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

For example:

例如:

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

Will result in:

将导致:

000086003D

#5


29  

I liked Steve's submissions, but he could have done without a couple of variables and saved several lines in the process.

我喜欢史蒂夫的建议,但他可以不用几个变量就能完成,并且在这个过程中节省了几行代码。

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);
}

What I like about this is that it's easy to see exactly what it's doing (instead of relying on some magic BigInteger black box conversion) and you're also free from having to worry about corner cases like leading-zeroes and stuff. This routine takes every 4-bit nibble and turns it into a hex char. And it's using a table lookup, so it's probably fast. It could probably be faster if you replace v/16 and v%16 with bitwise shifts and AND's, but I'm too lazy to test it right now.

我喜欢的是,很容易看到它正在做的事情(而不是依赖于一些神奇的BigInteger黑盒转换),而且您也不必担心像“导入-零”之类的角落案例。这个例程每4位咬一次,并把它变成一个十六进制字符。它使用的是表格查找,所以它可能是快速的。如果用位移位代替v/16和v%16,可能会更快,但我现在懒得去测试它。

#6


20  

I found Integer.toHexString to be a little slow. If you are converting many bytes, you may want to consider building an array of Strings containing "00".."FF" and use the integer as the index. I.e.

我发现整数。toHexString有点慢。如果您正在转换许多字节,您可能需要考虑构建包含“00”的字符串数组。使用整数作为索引。即。

hexString.append(hexArray[0xFF & messageDigest[i]]);

This is faster and ensures the correct length. Just requires the array of strings:

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

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"};

#7


12  

I've been looking for the same thing ... some good ideas here, but I ran a few micro benchmarks. I found the following to be the fastest (modified from Ayman's above and about 2x as fast, and about 50% faster than Steve's just above this one):

我一直在找同样的东西…这里有一些不错的想法,但我做了一些微观的基准测试。我发现以下是最快的(从Ayman的上面和大约2x修改得最快,比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);
}

Edit: Oops - missed that this is essentially the same as kgiannakakis's and so may strip off a leading 0. Still, modifying this to the following, it's still the fastest:

编辑:哦,错过了,这基本上和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;
}

#8


11  

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

    return sb.toString();
}

#9


6  

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

That's the shortest solution given what you already have. If you could convert the byte array to a numeric value, String.format can convert it to a hex string at the same time.

这是已知的最短解。如果可以将字节数组转换为数值,字符串。格式可以同时将其转换为十六进制字符串。

#10


5  

This solution is a little older school, and should be memory efficient.

这个解决方案是一个稍微老一点的学校,应该是内存效率。

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);
}

#11


5  

Another option

另一个选择

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();
}

#12


4  

In order to keep leading zeroes, here is a small variation on what has Paul suggested (eg md5 hash):

为了保持领先的零,这里有一个小的变化,保罗建议(如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));
}

Oops, this looks poorer than what's Ayman proposed, sorry for that

哎呀,这看起来比Ayman提出的要穷,抱歉。

#13


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();
}

#14


3  

It appears concat and append functions can be really slow. The following was MUCH faster for me (than my previous post). Changing to a char array in building the output was the key factor to speed it up. I have not compared to Hex.encodeHex suggested by Brandon DuRette.

看起来concat和append函数可以非常慢。下面的内容比我之前的文章要快得多。在构建输出时更改为char数组是加速其速度的关键因素。我没有和海克斯相比。由Brandon DuRette建议的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); }

#15


3  

Guava makes it pretty simple too:

番石榴也很简单:

BaseEncoding.base16().encode( bytes );

It's a nice alternative when Apache Commons is not available. It also has some nice controls of the output like:

当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"

#16


3  

I would use something like this for fixed length, like hashes:

我会用像这样的固定长度,比如哈希:

md5sum = String.format("%032x", new BigInteger(1, md.digest()));

The 0 in the mask does the padding...

掩码中的0做填充…

#17


2  

This what I am using for MD5 hashes:

这就是我使用的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);
}

EDIT: I've tested and I've noticed that with this also trailing zeros are cut. But this can only happen in the beginning, so you can compare with the expected length and pad accordingly.

编辑:我已经测试过了,而且我注意到,在这个后面还有一个0。但这只能在开始时发生,所以你可以与预期的长度和衬垫进行比较。

#18


2  

You can get it writing less without external libraries:

如果没有外部的库,可以少写一些:

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

#19


2  

This solution requires no bit-shifting or -masking, lookup tables, or external libraries, and is about as short as I can get:

这个解决方案不需要位移位或-屏蔽、查找表或外部库,并且是尽可能短的:

byte[] digest = new byte[16];       

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

fmt.toString()

#20


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);
}

#21


0  

IMHO all the solutions above that provide snippets to remove the leading zeroes are wrong.

IMHO上面的所有解决方案都提供了删除前导零的代码片段。

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

According to this snippet, 8 bits are taken from the byte array in an iteration, converted into an integer (since Integer.toHexString function takes int as argument) and then that integer is converted to the corresponding hash value. So, for example if you have 00000001 00000001 in binary, according to the code, the hexString variable would have 0x11 as the hex value whereas correct value should be 0x0101. Thus, while calculating MD5 we may get hashes of length <32 bytes(because of missing zeroes) which may not satisfy the cryptographically unique properties that MD5 hash does.

根据这段代码,在迭代中从字节数组中提取8位,转换为整数(因为整数。toHexString函数将int作为参数,然后将该整数转换为相应的散列值。例如,如果在二进制中有00000001 00000001,根据代码,hexString变量将有0x11作为十六进制值,而正确的值应该是0x0101。因此,在计算MD5时,我们可能会得到长度<32字节的散列(因为丢失的零),这可能无法满足MD5哈希所具有的加密特性。

The solution to the problem is replacing the above code snippet by the following snippet:

问题的解决方案是将上面的代码片段替换为以下代码片段:

byte messageDigest[] = algorithm.digest();
for (int i = 0; i < messageDigest.length; i++) {
    int temp=0xFF & messageDigest[i];
    String s=Integer.toHexString(temp);
    if(temp<=0x0F){
        s="0"+s;
    }
    hexString.append(s);
}

#22


0  

This is also equivalent but more concise using Apache util HexBin where the code reduces to

这也是等效的,但更简洁的是,使用Apache util HexBin,代码可以减少到。

HexBin.encode(messageDigest).toLowerCase();

#23


0  

This will give two-char long string for a byte.

这将为一个字节提供两字符长的字符串。

public String toString(byte b){
    final char[] Hex = new String("0123456789ABCDEF").toCharArray();
    return  "0x"+ Hex[(b & 0xF0) >> 4]+ Hex[(b & 0x0F)];
}

#24


0  

And how can you convert back again from ascii to byte array ?

怎样才能从ascii转换为字节数组呢?

i followed following code to convert to ascii given by Jemenake.

我遵循以下代码转换为Jemenake所提供的ascii。

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);
}

#25


0  

my variant

我的变体

    StringBuilder builder = new StringBuilder();
    for (byte b : bytes)
    {
        builder.append(Character.forDigit(b/16, 16));
        builder.append(Character.forDigit(b % 16, 16));
    }
    System.out.println(builder.toString());

it works for me.

它适合我。

#26


0  

Is that a faulty solution? (android java)

这是一个错误的解决方案吗?(安卓java)

    // Create MD5 Hash
    MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
    digest.update(s.getBytes());
    byte[] md5sum = digest.digest();
    BigInteger bigInt = new BigInteger(1, md5sum);
    String stringMD5 = bigInt.toString(16);
    // Fill to 32 chars
    stringMD5 = String.format("%32s", stringMD5).replace(' ', '0');
    return stringMD5;

So basically it replaces spaces with 0.

所以基本上用0代替空格。

#27


0  

I'm surprised that no one came up with the following solution:

我很惊讶没有人想到下面的解决方案:

StringWriter sw = new StringWriter();
com.sun.corba.se.impl.orbutil.HexOutputStream hex = new com.sun.corba.se.impl.orbutil.HexOutputStream(sw);
hex.write(byteArray);
System.out.println(sw.toString());