Как преобразовать байтовый массив в шестнадцатеричную строку в Java?


650

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


12
Почему бы просто не попробовать сначала и показать нам, что у вас есть. Тебе нечего терять и все получать. Integer имеет toHexString(...)метод, который может помочь, если это то, что вы ищете. Также String.format(...)можно сделать несколько простых трюков форматирования с использованием %2xстроки кода.
Судно на воздушной подушке, полное угрей


«Мне нужен точный шестнадцатеричный код в виде: 3a5f771c ...» - вы запросили точную форму, но не предоставили точного примера. Продолжая то, что вы предоставили, преобразуйте первые четыре байта в строку, затем объедините эллипсы в строку.
jww

1
С помощью потока в Java 8 это может быть просто реализовано как: static String byteArrayToHex (byte [] a) {return IntStream.range (0, a.length) .mapToObj (i -> String.format ("% 02x ", a [i])) .reduce ((acc, v) -> acc +" "+ v) .get (); }
Тибетти

Ответы:


902

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

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, который использует очень похожий код.)

Версия 2k20, относительно компактных строк Java 9:

private static final byte[] HEX_ARRAY = "0123456789ABCDEF".toByteArray();
public static String bytesToHex(byte[] bytes) {
    byte[] hexChars = new byte[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, StandardCharsets.UTF_8);
}

266
Я только что нашел javax.xml.bind.DataTypeConverter , часть стандартного дистрибутива. Почему это не возникает, когда вы Google такие проблемы? Много полезных инструментов, в том числе String printHexBinary(byte[])и byte[] parseHexBinary(String). printHexBinaryоднако намного (в 2 раза) медленнее, чем функция в этом ответе. (Я проверил источник; он использует stringBuilder. parseHexBinaryИспользует массив.) Правда, для большинства целей он достаточно быстр, и, вероятно, он у вас уже есть.
Может быть, WeSouldStealAVan

75
+1 за ответ, так как Android не имеет DataTypeConverter
Vaiden

7
@maybeWeCouldStealAVan: JDK 7 теперь с открытым исходным кодом. Мы должны представить патч для улучшения производительности для printHexBinary?
Кевинарпе

3
@maybeWeCouldStealAVan Не могли бы вы объяснить, как это работает. Я следую по большей части, но мне действительно нравится понимать, что происходит при использовании кода. Спасибо!
jjNford

24
javax.xml.bind.DataTypeConverterудаляется с Java 11.
Impaler

421

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

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

String foo = "I am a string";
byte[] bytes = foo.getBytes();
System.out.println( Hex.encodeHexString( bytes ) );

12
@cytinus - мое понижение произошло 4 месяца назад, поэтому я не совсем уверен, о чем я думал, но я, вероятно, возражал против размера библиотеки. Это небольшая функция в программе; нет необходимости добавлять такую ​​громоздкую библиотеку в проект для ее выполнения.
ArtOfWarfare

6
@ArtOfWarefare Я согласен, поэтому вместо import org.apache.commons.codec.*;вас можно было бы сделатьimport org.apache.commons.codec.binary.Hex;
cytinus

12
@ArtOfWarfare Я должен не согласиться. Единственное, что ужасно, это то, что библиотеки Apache Commons по умолчанию не включены в JRE и JDK. Есть несколько библиотек, которые настолько полезны, что по умолчанию они должны быть в вашем пути к классам, и это одна из них.
CorsiKa

29
Я настоятельно рекомендую этот ответ поменять местами как верхний ответ. Всегда голосуйте, чтобы использовать хорошо протестированную, производительную библиотеку с открытым исходным кодом над пользовательским кодом, который не улучшается.
Дмитрий Лихтен

6
Или, если вы используете BouncyCastle (org.bouncycastle : bcprov-jdk15on ), вы можете использовать этот класс:, org.bouncycastle.util.encoders.Hexс этим методом:String toHexString(byte[] data)
Гийом

320

Метод javax.xml.bind.DatatypeConverter.printHexBinary(), являющийся частью архитектуры Java для привязки XML (JAXB) , был удобным способом преобразования byte[]строки в шестнадцатеричную. DatatypeConverterКласс также включает множество других полезных методов данных манипуляций.

В Java 8 и более ранних версиях JAXB был частью стандартной библиотеки Java. Это было объявлено устаревшим с Java 9 и удалено с Java 11 , как часть попытки переместить все пакеты Java EE в свои собственные библиотеки. Это длинная история . Теперь javax.xml.bindего не существует, и если вы хотите использовать JAXB, который содержит DatatypeConverter, вам нужно установить JAXB API и JAXB Runtime от Maven.

Пример использования:

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

Приведет к:

000086003D

Этот ответ такой же, как этот .


13
Хорошее решение, хотя, к сожалению, оно не подходит для Android.
Казрико

@Kazriko, может быть, вы хотите прочитать code.google.com/p/dalvik/wiki/JavaxPackages . Это способ получить классы JavaScript в Android. Но если вы хотите конвертировать только в гекс, это не стоит проблем.
PhoneixS

13
DatatypeConverter больше не доступен с JDK 9
pmcollins

3
@PhoneixS Это все еще там, но не является частью времени выполнения по умолчанию (из-за модулей Java 9).
центре внимания

2
не полагайтесь на javax.xml.bind, он прекрасно компилируется, но его нельзя найти во время выполнения. если вы это сделаете, будьте готовы обработать java.lang.NoClassDefFoundError
Дмитрий

227

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

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

14
Это очень медленно, в среднем в 1000 раз медленнее (для длины 162 байта), чем в верхнем ответе. Избегайте использования String.Format, если производительность имеет значение.
pt123

8
Может быть, медленно. Это хорошо для вещей, происходящих время от времени, таких как логин или подобное.
Указатель нулевой

29
Если это медленно, и что? В моем случае это просто для оператора отладки, так что спасибо за этот фрагмент кода.
Викингстев

8
Повторное использование библиотеки путем добавления дополнительных JAR-файлов размером в несколько десятков килобайт будет неэффективным, если вам нужна только эта функция (на некоторых платформах, таких как Android, весь Jar-файл включается в конечное приложение). И иногда более короткий и понятный код лучше, когда производительность не требуется.
personne3000

2
@ personne3000, может быть, но в этом случае вам нужна поддержка потока, а не функция единого вызова. это легко понять и запомнить, и, следовательно, поддерживать.
Мартен Бодьюз

59

Решение Guava, для полноты:

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

Сейчас hexесть "48656c6c6f20776f726c64".


В Гуаве вы также можете использовать new HashCode(bytes).toString().
mfulton26

1
По состоянию на Гуава 22,0 этоHashCode.fromBytes(checksum).toString()
Devstr

43

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


56
Этот oneliner сбрасывает ведущие ноль байтов.
Войку

@Voicu ... И это добавит начальный ноль в 50% случаев.
Maarten Bodewes

27

Вот несколько общих опций, упорядоченных от простого (однострочный) до сложного (огромная библиотека). Если вы заинтересованы в производительности, см. Микро тесты ниже.

Вариант 1: фрагмент кода - простой

Одним из очень простых решений является использование BigIntegerшестнадцатеричного представления:

new BigInteger(1, someByteArray).toString(16)

Обратите внимание, что, поскольку он обрабатывает числа, а не произвольные строки байтов, он пропускает ведущие нули - это может или не может быть тем, что вы хотите (например, 000AE3против 0AE33-байтового ввода). Это также очень медленно, примерно в 100 раз медленнее по сравнению со следующим вариантом.

Вариант 2: фрагмент кода - расширенный

Вот полнофункциональный, копируемый и вставляемый фрагмент кода, поддерживающий верхний / нижний регистр и порядковый номер . Он оптимизирован для минимизации сложности памяти и максимизации производительности и должен быть совместим со всеми современными версиями Java (5+).

private static final char[] LOOKUP_TABLE_LOWER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
private static final char[] LOOKUP_TABLE_UPPER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};

public static String encode(byte[] byteArray, boolean upperCase, ByteOrder byteOrder) {

    // our output size will be exactly 2x byte-array length
    final char[] buffer = new char[byteArray.length * 2];

    // choose lower or uppercase lookup table
    final char[] lookup = upperCase ? LOOKUP_TABLE_UPPER : LOOKUP_TABLE_LOWER;

    int index;
    for (int i = 0; i < byteArray.length; i++) {
        // for little endian we count from last to first
        index = (byteOrder == ByteOrder.BIG_ENDIAN) ? i : byteArray.length - i - 1;

        // extract the upper 4 bit and look up char (0-A)
        buffer[i << 1] = lookup[(byteArray[index] >> 4) & 0xF];
        // extract the lower 4 bit and look up char (0-A)
        buffer[(i << 1) + 1] = lookup[(byteArray[index] & 0xF)];
    }
    return new String(buffer);
}

public static String encode(byte[] byteArray) {
    return encode(byteArray, false, ByteOrder.BIG_ENDIAN);
}

Полный исходный код с лицензией Apache v2 и декодером можно найти здесь .

Вариант 3. Использование небольшой оптимизированной библиотеки: bytes-java

Работая над моим предыдущим проектом, я создал этот небольшой инструментарий для работы с байтами в Java. Он не имеет внешних зависимостей и совместим с Java 7+. Он включает, среди прочего, очень быстрый и хорошо протестированный HEX en / decoder:

import at.favre.lib.bytes.Bytes;
...
Bytes.wrap(someByteArray).encodeHex()

Вы можете проверить это на Github: bytes-java .

Вариант 4: Кодек Apache Commons

Конечно, есть хорошие кодеки . ( предупреждающее мнение впереди ) Во время работы над проектом, описанным выше, я проанализировал код и был весьма разочарован; множество дублированных неорганизованных кодов, устаревших и экзотических кодеков, вероятно, полезно только для очень немногих и довольно изощренных и медленных реализаций популярных кодеков (особенно Base64). Поэтому я бы принял обоснованное решение, если вы хотите использовать его или альтернативу. В любом случае, если вы все еще хотите его использовать, вот фрагмент кода:

import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(someByteArray));

Вариант 5: Google Guava

Чаще всего у вас уже есть Guava в качестве зависимости. Если это так, просто используйте:

import com.google.common.io.BaseEncoding;
...
BaseEncoding.base16().lowerCase().encode(someByteArray);

Вариант 6: Spring Security

Если вы используете Spring Framework с Spring Security, вы можете использовать следующее:

import org.springframework.security.crypto.codec.Hex
...
new String(Hex.encode(someByteArray));

Вариант 7: Надувной замок

Если вы уже используете инфраструктуру безопасности Bouncy Castle, вы можете использовать ее Hexутилиту:

import org.bouncycastle.util.encoders.Hex;
...
Hex.toHexString(someByteArray);

Вариант 8 не совсем: совместимость с Java 9+ или «Не используйте JAXBs javax / xml / bind / DatatypeConverter»

В предыдущих версиях Java (8 и ниже) код Java для JAXB был включен как зависимость времени выполнения. Начиная с Java 9 и Jigsaw modularisation ваш код не может получить доступ к другому коду вне своего модуля без явного объявления. Так что будьте внимательны, если вы получите исключение, подобное:

java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

при работе на JVM с Java 9+. Если это так, то переключите реализации на любую из альтернатив, описанных выше. Смотрите также этот вопрос .


Микро Тесты

Ниже приведены результаты простого JMH микро эталонного кодирование байтовых массивов различных размеров . Значения - это операции в секунду, поэтому чем выше , тем лучше. Обратите внимание, что микропроцессоры очень часто не отражают поведение в реальном мире, поэтому воспринимайте эти результаты с недоверием.

| Name (ops/s)         |    16 byte |    32 byte |  128 byte | 0.95 MB |
|----------------------|-----------:|-----------:|----------:|--------:|
| Opt1: BigInteger     |  2,088,514 |  1,008,357 |   133,665 |       4 |
| Opt2/3: Bytes Lib    | 20,423,170 | 16,049,841 | 6,685,522 |     825 |
| Opt4: Apache Commons | 17,503,857 | 12,382,018 | 4,319,898 |     529 |
| Opt5: Guava          | 10,177,925 |  6,937,833 | 2,094,658 |     257 |
| Opt6: Spring         | 18,704,986 | 13,643,374 | 4,904,805 |     601 |
| Opt7: BC             |  7,501,666 |  3,674,422 | 1,077,236 |     152 |
| Opt8: JAX-B          | 13,497,736 |  8,312,834 | 2,590,940 |     346 |

Спецификации: JDK 8u202, i7-7700K, Win10, 24 ГБ RAM. Смотрите полный тест здесь .




18

Я нашел три разных способа здесь: 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();
}

Другие методы выполнялись на моей 64-байтовой выборке за 5 мс, этот работает за 0 мс. Вероятно, лучше всего из-за отсутствия каких-либо других строковых функций, таких как формат.
Джозеф Ласт

if (raw == null) return nullне подведет быстро. Зачем тебе когда-нибудь использовать nullключ?
Maarten Bodewes

Я полагаю, это привычка вводить подтверждение. В этом случае мы предотвращаем любое исключение ссылки Null и оставляем вызывающей стороне обрабатывать неверные данные.
Майкл Бисбьерг

16

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

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

6
Почему бы не инициализировать BYTE2HEXмассив простым forциклом?
icza

@icza Возможно ли это даже с помощью поля static final (aka constant)?
Невелис

1
@nevelis Может быть назначен в static { }блоке.
よ ル ち ゃ ん だ よ

1
@icza, потому что быстрее жестко кодировать таблицу поиска, чем генерировать ее. Здесь сложность памяти торгуется со сложностью времени, т.е. нужно больше памяти, но быстрее (чуть-чуть с обоих концов)
Патрик Фавр

8

Как насчет этого?

    String byteToHex(final byte[] hash)
    {
        Formatter formatter = new Formatter();
        for (byte b : hash)
        {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

3

Нам не нужно использовать какую-либо внешнюю библиотеку или писать код на основе циклов и констант.
Достаточно только этого:

byte[] theValue = .....
String hexaString = new BigInteger(1, theValue).toString(16);

1
Это очень похоже на ответ вечно запутанного Гая.
Скрат

2

Я предпочитаю использовать это:

final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes, int offset, int count) {
    char[] hexChars = new char[count * 2];
    for ( int j = 0; j < count; j++ ) {
        int v = bytes[j+offset] & 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
}

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


Первоначальный вопрос был для байта [] в строку. Посмотрите шестнадцатеричное число в байтах [] или задайте другой вопрос, @NonExistent.
Бамако

2

Я обычно использую следующий метод для заявления debuf, но я не знаю, является ли это лучшим способом сделать это или нет

private static String digits = "0123456789abcdef";

public static String toHex(byte[] data){
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i != data.length; i++)
    {
        int v = data[i] & 0xff;
        buf.append(digits.charAt(v >> 4));
        buf.append(digits.charAt(v & 0xf));
    }
    return buf.toString();
}

2
Если debuffer имеет плохой день, попробуйте cluing в StringBuilder конкретизации с количеством символов для поддержки: StringBuilder buf = new StringBuilder(data.length * 2);.
седобородый

2

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

org.apache.commons.codec.binary.Hex

может быть, у вас есть ...

org.apache.xerces.impl.dv.util.HexBin


2

Если вы используете платформу Spring Security, вы можете использовать:

import org.springframework.security.crypto.codec.Hex

final String testString = "Test String";
final byte[] byteArray = testString.getBytes();
System.out.println(Hex.encode(byteArray));

2

Добавление утилиты jar для простой функции не является хорошим вариантом. Вместо этого соберите свои собственные служебные классы. Следующее возможно быстрее реализации.

public class ByteHex {

    public static int hexToByte(char ch) {
        if ('0' <= ch && ch <= '9') return ch - '0';
        if ('A' <= ch && ch <= 'F') return ch - 'A' + 10;
        if ('a' <= ch && ch <= 'f') return ch - 'a' + 10;
        return -1;
    }

    private static final String[] byteToHexTable = new String[]
    {
        "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"
    };

    private static final String[] byteToHexTableLowerCase = new String[]
    {
        "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"
    };

    public static String byteToHex(byte b){
        return byteToHexTable[b & 0xFF];
    }

    public static String byteToHex(byte[] bytes){
        if(bytes == null) return null;
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(byte b : bytes) sb.append(byteToHexTable[b & 0xFF]);
        return sb.toString();
    }

    public static String byteToHex(short[] bytes){
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(short b : bytes) sb.append(byteToHexTable[((byte)b) & 0xFF]);
        return sb.toString();
    }

    public static String byteToHexLowerCase(byte[] bytes){
        StringBuilder sb = new StringBuilder(bytes.length*2);
        for(byte b : bytes) sb.append(byteToHexTableLowerCase[b & 0xFF]);
        return sb.toString();
    }

    public static byte[] hexToByte(String hexString) {
        if(hexString == null) return null;
        byte[] byteArray = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i += 2) {
            byteArray[i / 2] = (byte) (hexToByte(hexString.charAt(i)) * 16 + hexToByte(hexString.charAt(i+1)));
        }
        return byteArray;
    }

    public static byte hexPairToByte(char ch1, char ch2) {
        return (byte) (hexToByte(ch1) * 16 + hexToByte(ch2));
    }


}

1

Небольшой вариант решения, предложенного @maybewecouldstealavan, который позволяет визуально объединять N байтов в выходную шестнадцатеричную строку:

 final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
 final static char BUNDLE_SEP = ' ';

public static String bytesToHexString(byte[] bytes, int bundleSize /*[bytes]*/]) {
        char[] hexChars = new char[(bytes.length * 2) + (bytes.length / bundleSize)];
        for (int j = 0, k = 1; j < bytes.length; j++, k++) {
                int v = bytes[j] & 0xFF;
                int start = (j * 2) + j/bundleSize;

                hexChars[start] = HEX_ARRAY[v >>> 4];
                hexChars[start + 1] = HEX_ARRAY[v & 0x0F];

                if ((k % bundleSize) == 0) {
                        hexChars[start + 2] = BUNDLE_SEP;
                }   
        }   
        return new String(hexChars).trim();    
}

Это:

bytesToHexString("..DOOM..".toCharArray().getBytes(), 2);
2E2E 444F 4F4D 2E2E

bytesToHexString("..DOOM..".toCharArray().getBytes(), 4);
2E2E444F 4F4D2E2E

1

На этой странице не найдено ни одного решения, которое бы не

  1. Используйте цикл
  2. Используйте javax.xml.bind.DatatypeConverter, который прекрасно компилируется, но часто выдает java.lang.NoClassDefFoundError во время выполнения.

Вот решение, в котором нет недостатков, указанных выше (хотя никаких обещаний у меня нет и других недостатков)

import java.math.BigInteger;

import static java.lang.System.out;
public final class App2 {
    // | proposed solution.
    public static String encode(byte[] bytes) {          
        final int length = bytes.length;

        // | BigInteger constructor throws if it is given an empty array.
        if (length == 0) {
            return "00";
        }

        final int evenLength = (int)(2 * Math.ceil(length / 2.0));
        final String format = "%0" + evenLength + "x";         
        final String result = String.format (format, new BigInteger(bytes));

        return result;
    }

    public static void main(String[] args) throws Exception {
        // 00
        out.println(encode(new byte[] {})); 

        // 01
        out.println(encode(new byte[] {1})); 

        //203040
        out.println(encode(new byte[] {0x20, 0x30, 0x40})); 

        // 416c6c20796f75722062617365206172652062656c6f6e6720746f2075732e
        out.println(encode("All your base are belong to us.".getBytes()));
    }
}   

Я не мог получить это под 62 кодами операций, но если вы можете жить без заполнения 0 в случае, если первый байт меньше 0x10, то в следующем решении используются только 23 кода операции. Действительно показывает, как «легко реализовать себя» решения, такие как «pad с нулем, если длина строки нечетна», могут стать довольно дорогими, если собственная реализация еще не доступна (или в этом случае, если BigInteger имел возможность ставить префикс с нулями в нанизывать).

public static String encode(byte[] bytes) {          
    final int length = bytes.length;

    // | BigInteger constructor throws if it is given an empty array.
    if (length == 0) {
        return "00";
    }

    return new BigInteger(bytes).toString(16);
}

1

Мое решение основано на решении может быть WeCouldStealAVan, но не опирается на какие-либо дополнительные таблицы поиска. Он не использует хаки типа int-to-char (на самом деле, Character.forDigit()делает это, выполняя некоторое сравнение, чтобы проверить, что на самом деле является цифрой) и, следовательно, может быть немного медленнее. Пожалуйста, не стесняйтесь использовать его где угодно. Приветствия.

public static String bytesToHex(final byte[] bytes)
{
    final int numBytes = bytes.length;
    final char[] container = new char[numBytes * 2];

    for (int i = 0; i < numBytes; i++)
    {
        final int b = bytes[i] & 0xFF;

        container[i * 2] = Character.forDigit(b >>> 4, 0x10);
        container[i * 2 + 1] = Character.forDigit(b & 0xF, 0x10);
    }

    return new String(container);
}

0

// Сдвиг байтов более эффективен // Вы тоже можете использовать этот

public static String getHexString (String s) 
{
    byte[] buf = s.getBytes();

    StringBuffer sb = new StringBuffer();

    for (byte b:buf)
    {
        sb.append(String.format("%x", b));
    }


        return sb.toString();
}

0

Если вы ищете такой же байтовый массив для python, я преобразовал эту реализацию Java в python.

class ByteArray:

@classmethod
def char(cls, args=[]):
    cls.hexArray = "0123456789ABCDEF".encode('utf-16')
    j = 0
    length = (cls.hexArray)

    if j < length:
        v = j & 0xFF
        hexChars = [None, None]
        hexChars[j * 2] = str( cls.hexArray) + str(v)
        hexChars[j * 2 + 1] = str(cls.hexArray) + str(v) + str(0x0F)
        # Use if you want...
        #hexChars.pop()

    return str(hexChars)

array = ByteArray()
print array.char(args=[])

0
  public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
      data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
        + Character.digit(s.charAt(i+1), 16));
    }
  return data;
  } 

0

Вот такая java.util.Base64реализация (частичная), не правда ли?

public class Base16/*a.k.a. Hex*/ {
    public static class Encoder{
        private static char[] toLowerHex={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
        private static char[] toUpperHex={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
        private boolean upper;
        public Encoder(boolean upper) {
            this.upper=upper;
        }
        public String encode(byte[] data){
            char[] value=new char[data.length*2];
            char[] toHex=upper?toUpperHex:toLowerHex;
            for(int i=0,j=0;i<data.length;i++){
                int octet=data[i]&0xFF;
                value[j++]=toHex[octet>>4];
                value[j++]=toHex[octet&0xF];
            }
            return new String(value);
        }
        static final Encoder LOWER=new Encoder(false);
        static final Encoder UPPER=new Encoder(true);
    }
    public static Encoder getEncoder(){
        return Encoder.LOWER;
    }
    public static Encoder getUpperEncoder(){
        return Encoder.UPPER;
    }
    //...
}

0
private static String bytesToHexString(byte[] bytes, int length) {
        if (bytes == null || length == 0) return null;

        StringBuilder ret = new StringBuilder(2*length);

        for (int i = 0 ; i < length ; i++) {
            int b;

            b = 0x0f & (bytes[i] >> 4);
            ret.append("0123456789abcdef".charAt(b));

            b = 0x0f & bytes[i];
            ret.append("0123456789abcdef".charAt(b));
        }

        return ret.toString();
    }

0
Converts bytes data to hex characters

@param bytes byte array to be converted to hex string
@return byte String in hex format

private static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for (int j = 0; j < bytes.length; j++) {
        v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.