Как преобразовать байтовый массив в шестнадцатеричную строку в Java? - PullRequest
580 голосов
/ 11 марта 2012

У меня есть байтовый массив, заполненный шестнадцатеричными числами, и печатать его простым способом довольно бессмысленно, потому что там много непечатаемых элементов. Мне нужен точный шестнадцатеричный код в виде: 3a5f771c

Ответы [ 25 ]

826 голосов
/ 25 марта 2012

Из обсуждения здесь , и особенно этот ответ, это функция, которую я сейчас использую:

private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(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] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

Мои собственные крошечные тесты (миллион байт)тысячу раз, 256 байт (10 миллионов раз) показали, что это намного быстрее, чем любая другая альтернатива, примерно вдвое меньше для длинных массивов.По сравнению с ответом, который я получил, переключение на побитовые операции - как предлагалось в обсуждении - сократило время на длинные массивы примерно на 20%.(Изменить: когда я говорю, что это быстрее, чем альтернативы, я имею в виду альтернативный код, предложенный в обсуждениях. Производительность эквивалентна кодеку Commons, который использует очень похожий код.)

374 голосов
/ 11 марта 2012

В библиотеке Apache Commons Codec есть класс Hex для выполнения именно этого типа работы.

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

String foo = "I am a string";
byte[] bytes = foo.getBytes();
System.out.println( Hex.encodeHexString( bytes ) );
313 голосов
/ 24 февраля 2014

Используйте 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};
System.out.println(javax.xml.bind.DatatypeConverter.printHexBinary(bytes));

Результатом будет:

000086003D

Как вы можете видеть, эта команда извлечет шестнадцатеричную строку, представляющую массив байтов с ведущими нулями.

Этот ответ в основном такой же, как и в вопросе В Java, как преобразовать байтовый массив в строку шестнадцатеричных цифр, сохраняя ведущие нули?

207 голосов
/ 22 октября 2012

Самое простое решение, без внешних библиотек, без констант цифр:

public static String byteArrayToHex(byte[] a) {
   StringBuilder sb = new StringBuilder(a.length * 2);
   for(byte b: a)
      sb.append(String.format("%02x", b));
   return sb.toString();
}
49 голосов
/ 07 апреля 2016

Раствор гуавы, для полноты:

import com.google.common.io.BaseEncoding;
...
byte[] bytes = "Hello world".getBytes(StandardCharsets.UTF_8);
final String hex = BaseEncoding.base16().lowerCase().encode(bytes);

Теперь hex - это "48656c6c6f20776f726c64".

41 голосов
/ 04 ноября 2012

Этот простой oneliner работает для меня
String result = new BigInteger(1, inputBytes).toString(16);
РЕДАКТИРОВАТЬ - Использование этого удалит ведущие нули, но они работали для моего варианта использования. Спасибо @Voicu за указание на это

24 голосов
/ 12 мая 2016

Использовать класс DataTypeConverter javax.xml.bind.DataTypeConverter

String hexString = DatatypeConverter.printHexBinary(bytes[] raw);

16 голосов
/ 22 января 2017

Я бы использовал что-то подобное для фиксированной длины, например, хэши:

md5sum = String.format("%032x", new BigInteger(1, md.digest()));
15 голосов
/ 29 января 2014

При незначительной стоимости хранения таблицы соответствия эта реализация проста и очень быстра.

 private static final char[] BYTE2HEX=(
    "000102030405060708090A0B0C0D0E0F"+
    "101112131415161718191A1B1C1D1E1F"+
    "202122232425262728292A2B2C2D2E2F"+
    "303132333435363738393A3B3C3D3E3F"+
    "404142434445464748494A4B4C4D4E4F"+
    "505152535455565758595A5B5C5D5E5F"+
    "606162636465666768696A6B6C6D6E6F"+
    "707172737475767778797A7B7C7D7E7F"+
    "808182838485868788898A8B8C8D8E8F"+
    "909192939495969798999A9B9C9D9E9F"+
    "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"+
    "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"+
    "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"+
    "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"+
    "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"+
    "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF").toCharArray();
   ; 

  public static String getHexString(byte[] bytes) {
    final int len=bytes.length;
    final char[] chars=new char[len<<1];
    int hexIndex;
    int idx=0;
    int ofs=0;
    while (ofs<len) {
      hexIndex=(bytes[ofs++] & 0xFF)<<1;
      chars[idx++]=BYTE2HEX[hexIndex++];
      chars[idx++]=BYTE2HEX[hexIndex];
    }
    return new String(chars);
  }
15 голосов
/ 11 марта 2012

Я нашел три разных способа здесь: http://www.rgagnon.com/javadetails/java-0596.html

Самый элегантный, как он также отмечает, я думаю, что это:

static final String HEXES = "0123456789ABCDEF";
public static String getHex( byte [] raw ) {
    if ( raw == null ) {
        return null;
    }
    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();
}
...