Java-код Для преобразования байта в шестнадцатеричный


184

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

Есть ли в Java какая-либо функция для преобразования байтового массива в шестнадцатеричный?


2
То, что вы называете байтовым массивом в Java, называется байтовой строкой на других языках (например, docs.racket-lang.org/guide/bytestrings.html )
Патрик Фавр,

Ответы:


311
    byte[] bytes = {-1, 0, 1, 2, 3 };
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
        sb.append(String.format("%02X ", b));
    }
    System.out.println(sb.toString());
    // prints "FF 00 01 02 03 "

Смотрите также

  • java.util.Formatter синтаксис
    • %[flags][width]conversion
      • Флаг '0'- результат будет дополнен нулями
      • Ширина 2
      • Преобразование 'X'- результат форматируется как шестнадцатеричное целое, заглавные

Глядя на текст вопроса, также возможно, что это то, что запрашивается:

    String[] arr = {"-1", "0", "10", "20" };
    for (int i = 0; i < arr.length; i++) {
        arr[i] = String.format("%02x", Byte.parseByte(arr[i]));
    }
    System.out.println(java.util.Arrays.toString(arr));
    // prints "[ff, 00, 0a, 14]"

Несколько ответов здесь использует Integer.toHexString(int); это выполнимо, но с некоторыми оговорками. Так как параметр является intрасширением, преобразование примитива выполняется в byteаргумент, который включает расширение знака.

    byte b = -1;
    System.out.println(Integer.toHexString(b));
    // prints "ffffffff"

8-разрядный byte, который подписан в Java, расширен до 32-разрядного знака int. Чтобы эффективно отменить это расширение знака, можно замаскировать byteс 0xFF.

    byte b = -1;
    System.out.println(Integer.toHexString(b & 0xFF));
    // prints "ff"

Другая проблема с использованием toHexStringзаключается в том, что он не дополняется нулями:

    byte b = 10;
    System.out.println(Integer.toHexString(b & 0xFF));
    // prints "a"

Оба этих фактора должны сделать String.formatрешение более предпочтительным.

Ссылки


@Vivek: что такое «чрезвычайно большая ценность»? Какой вход и какой выход?
полигенасмазочные материалы

Позвольте мне объяснить еще раз .. У меня есть коллекция байтовых строк в массиве. Но то, что я должен сделать, это проанализировать каждый байт отдельно. Итак, я не хочу работать со всем массивом, но с отдельной строкой байта за раз, которая является одним из компонентов этого массива. Путаница возникла из-за слова " массив». Теперь в приведенном ниже коде: «byte bv = 10; String hexString = Integer.toHexString (bv);» CAse 1 (Получено байт: 68 Вывод шестнадцатеричных данных: 44) Случай: 2 (Получен байт: Вывод шестнадцатеричных символов:: ffffffd2) ......... Почему я получаю такой неожиданный результат для некоторых значений?
Вивек

1
@Vivek: прочитайте мой ответ об использовании toHexString. Вы должны замаскировать это & 0xFF, то Integer.toHexString(-46 & 0xFF)есть "d2".
полигенасмазочные материалы

@polygenelubricants: Большое спасибо .. Кажется, наконец-то код работает нормально. Безопасно ли сейчас использовать функцию toHexString? Или могут быть некоторые лазейки с подходом?
Вивек

1
@Vivek: это «безопасно», вам просто нужно быть осторожным и каждый раз маскировать byteзначение & 0xFF. formatрешение выше , может также потребоваться маскирование в зависимости от того, что вы на самом деле , используя в качестве аргумента.
полигенасмазочные материалы

65

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

Прежде всего, что мы пытаемся сделать? Мы хотим преобразовать байтовое значение (или массив байтов) в строку, которая представляет шестнадцатеричное значение в ASCII. Итак, первый шаг - выяснить, что такое байт в Java:

Байтовый тип данных представляет собой 8-разрядное целое число со знаком в виде двоичного числа со знаком . Он имеет минимальное значение -128 и максимальное значение 127 (включительно). Байтовый тип данных может быть полезен для сохранения памяти в больших массивах, где экономия памяти действительно имеет значение. Их также можно использовать вместо int, где их пределы помогают уточнить ваш код; тот факт, что диапазон переменной ограничен, может служить формой документации.

Что это значит? Несколько вещей: во-первых, и самое главное, это означает, что мы работаем с 8-битными . Так, например, мы можем записать число 2 как 0000 0010. Однако, поскольку оно является дополнением до двух, мы пишем отрицательное число 2, например: 1111 1110. Что также означает, что преобразование в шестнадцатеричное является очень простым. То есть вы просто конвертируете каждый 4-битный сегмент прямо в гекс. Обратите внимание, что для понимания отрицательных чисел в этой схеме вам сначала нужно понять дополнение к двум. Если вы еще не понимаете дополнение к двум, вы можете прочитать отличное объяснение здесь: http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html


Преобразование дополнения до двух в Hex в целом

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

Примеры

Пример 1: конвертировать 2 в шестнадцатеричное.

1) Сначала преобразуйте 2 в двоичный код в дополнении до двух:

2 (base 10) = 0000 0010 (base 2)

2) Теперь преобразуйте двоичный файл в гекс:

0000 = 0x0 in hex
0010 = 0x2 in hex

therefore 2 = 0000 0010 = 0x02. 

Пример 2: конвертировать -2 (в дополнении до двух) в шестнадцатеричное.

1) Сначала преобразуйте -2 в двоичный код в дополнении до двух:

-2 (base 10) = 0000 0010 (direct conversion to binary) 
               1111 1101 (invert bits)
               1111 1110 (add 1)
therefore: -2 = 1111 1110 (in two's complement)

2) Теперь преобразуйте в Hex:

1111 = 0xF in hex
1110 = 0xE in hex

therefore: -2 = 1111 1110 = 0xFE.


Делать это в Java

Теперь, когда мы рассмотрели эту концепцию, вы обнаружите, что мы можем достичь того, чего хотим, с помощью простой маскировки и сдвига. Главное, что нужно понять, это то, что байт, который вы пытаетесь преобразовать, уже дополняет два. Вы не делаете это преобразование самостоятельно. Я думаю, что это серьезная путаница в этом вопросе. Возьмем для примера следующий байтовый массив:

byte[] bytes = new byte[]{-2,2};

Мы просто вручную конвертировали их в шестнадцатеричные, но как мы можем это сделать на Java? Вот как:

Шаг 1: Создайте StringBuffer для хранения наших вычислений.

StringBuffer buffer = new StringBuffer();

Шаг 2. Изолируйте биты высшего порядка, преобразуйте их в шестнадцатеричные и добавьте в буфер.

Учитывая двоичное число 1111 1110, мы можем выделить биты более высокого порядка, сначала сместив их на 4, а затем обнулив оставшуюся часть числа. Логически это просто, однако детали реализации в Java (и многих языках) вносят помехи из-за расширения знака. По сути, когда вы сдвигаете значение байта, Java сначала преобразует ваше значение в целое число, а затем выполняет расширение знака. Таким образом, хотя вы ожидаете, что 1111 1110 >> 4 будет 0000 1111, в действительности на Java это представляется как дополнение к двум 0xFFFFFFFF!

Итак, возвращаясь к нашему примеру:

1111 1110 >> 4 (shift right 4) = 1111 1111 1111 1111 1111 1111 1111 1111 (32 bit sign-extended number in two's complement)

Затем мы можем выделить биты с помощью маски:

1111 1111 1111 1111 1111 1111 1111 1111 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1111
therefore: 1111 = 0xF in hex. 

В Java мы можем сделать все это одним выстрелом:

Character.forDigit((bytes[0] >> 4) & 0xF, 16);

Функция forDigit просто отображает переданное вами число на набор шестнадцатеричных чисел 0-F.

Шаг 3: Далее нам нужно выделить биты младшего разряда. Поскольку нужные нам биты уже находятся в правильном положении, мы можем просто замаскировать их:

1111 1110 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1110 (recall sign extension from before)
therefore: 1110 = 0xE in hex.  

Как и раньше, в Java мы можем сделать все это за один раз:

Character.forDigit((bytes[0] & 0xF), 16);

Собрав все это вместе, мы можем сделать это как цикл for и преобразовать весь массив:

for(int i=0; i < bytes.length; i++){
    buffer.append(Character.forDigit((bytes[i] >> 4) & 0xF, 16));
    buffer.append(Character.forDigit((bytes[i] & 0xF), 16));
}

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


4
лучший ответ! Симметричная реализация шестнадцатеричной строки в байт будет преобразована, а затем использовать Character.digit(), как(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
ericbn

21

Самый быстрый способ, который я пока нашел, это сделать следующее:

private static final String    HEXES    = "0123456789ABCDEF";

static String getHex(byte[] raw) {
    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();
}

Это ~ в 50 раз быстрее чем String.format. если вы хотите проверить это:

public class MyTest{
    private static final String    HEXES        = "0123456789ABCDEF";

    @Test
    public void test_get_hex() {
        byte[] raw = {
            (byte) 0xd0, (byte) 0x0b, (byte) 0x01, (byte) 0x2a, (byte) 0x63,
            (byte) 0x78, (byte) 0x01, (byte) 0x2e, (byte) 0xe3, (byte) 0x6c,
            (byte) 0xd2, (byte) 0xb0, (byte) 0x78, (byte) 0x51, (byte) 0x73,
            (byte) 0x34, (byte) 0xaf, (byte) 0xbb, (byte) 0xa0, (byte) 0x9f,
            (byte) 0xc3, (byte) 0xa9, (byte) 0x00, (byte) 0x1e, (byte) 0xd5,
            (byte) 0x4b, (byte) 0x89, (byte) 0xa3, (byte) 0x45, (byte) 0x35,
            (byte) 0xd6, (byte) 0x10,
        };

        int N = 77777;
        long t;

        {
            t = System.currentTimeMillis();
            for (int i = 0; i < N; i++) {
                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)));
                }
                hex.toString();
            }
            System.out.println(System.currentTimeMillis() - t); // 50
        }

        {
            t = System.currentTimeMillis();
            for (int i = 0; i < N; i++) {
                StringBuilder hex = new StringBuilder(2 * raw.length);
                for (byte b : raw) {
                    hex.append(String.format("%02X", b));
                }
                hex.toString();
            }
            System.out.println(System.currentTimeMillis() - t); // 2535
        }

    }
}

Изменить : только что нашел что-то немного быстрее, и он держится на одной строке, но не совместим с JRE 9. Используйте на свой страх и риск

import javax.xml.bind.DatatypeConverter;

DatatypeConverter.printHexBinary(raw);

2
DatatypeConverter больше не доступен в Java 9. Опасно то, что код, использующий его, будет компилироваться в Java 1.8 или более ранней (Java 9 с более ранними настройками исходного кода), но получит исключение времени выполнения в Java 9.
Стивен М - на забастовке -

Второй момент @StephenMs: использование этого с jre9 приведет к сбою с исключением ClassNotFound
Патрик Фавр

На самом деле можно просто извлечь метод исходного кода printHexBinary из src.zip из jdk, который кажется в 1 раз быстрее, чем первый метод.
Фрукты

1
Если вы работаете с массивом char для константы HEXES, а не String и charAt (), вы получаете ~ 20% больше скорости.
Диоргио

15

Попробуйте так:

byte bv = 10;
String hexString = Integer.toHexString(bv);

Работа с массивом (если я вас правильно понял):

byte[] bytes = {9, 10, 11, 15, 16};
StringBuffer result = new StringBuffer();
for (byte b : bytes) {
    result.append(String.format("%02X ", b));
    result.append(" "); // delimiter
}
return result.toString();

Как уже упоминалось, полигенные смазочные материалы String.format()- это правильный ответ по сравнению с Integer.toHexString()(поскольку он правильно работает с отрицательными числами).


2
Это будет означать расширение, например, попробуйте -1.
полигенасмазочные материалы

байт bv = 10; String hexString = Integer.toHexString (bv); Кажется, это работает лучше ... Я могу применить его индивидуально к каждому элементу массива. Другой код (Работа с массивом) возвращает слишком большое значение. Что может быть причиной этого?
Вивек

@Vivek, это потому, что в случае bvэтого возвращает один шестнадцатеричный символ . Принимая во внимание, что остальная часть кода возвращает строку шестнадцатеричных символов . Я изменил код с помощью разделителя, чтобы вы могли понять его сейчас.
0x2D9A3

@Bar: вы все еще можете использовать, Integer.toHexStringесли вы маскируете byteс, 0xFFчтобы отменить расширение знака.
полигенасмазочные материалы

Причина 1 (Получено байт: 68 Вывод в шестнадцатеричном формате: 44) Случай: 2 (Получено байтов: Вывод в шестнадцатеричном формате:: ffffffd2) Я получаю неожиданные выходные значения в случае отрицательных байтовых массивов ... Как с этим справиться?
Вивек

13

Лучшее решение - это задира:

String hex=DatatypeConverter.printHexBinary(byte[] b);

как упомянуто здесь


4
DatatypeConverter больше не доступен в Java 9. Опасно то, что код, использующий его, будет компилироваться в Java 1.8 или более ранней (Java 9 с более ранними настройками исходного кода), но получит исключение времени выполнения в Java 9.
Стивен М - на забастовке -

Грустно, когда вы говорите, что это не в jdk9. new BigInteger(byteArray).toString(16)это путь тогда. Есть ли проблемы с этим?
prayagupd

Может быть, не проблемы с производством, но он пропустит ведущие нули (так как они бессмысленны для числа, такого как BigInteger)
Friso

Похоже, это все еще в java 9 документах , так что, кажется, можно использовать его все еще из того, что я могу сказать
Брэд Паркс

я думаю, как объяснено здесь, все еще нормально использовать для java9, но будет удалено в будущих выпусках java. вы также все еще сможете использовать его с «новым» автономным модулем jaxb начиная с версии 2.3.0 .
рысь

11

Если вам нужно шестнадцатеричное представление постоянной ширины, т.е. 0Aвместо A, чтобы вы могли однозначно восстановить байты, попробуйте format():

StringBuilder result = new StringBuilder();
for (byte bb : byteArray) {
    result.append(String.format("%02X", bb));
}
return result.toString();

11

Короткий и простой способ преобразования byte[]в шестнадцатеричную строку с помощью BigInteger:

import java.math.BigInteger;

byte[] bytes = new byte[] {(byte)255, 10, 20, 30};
String hex = new BigInteger(1, bytes).toString(16);
System.out.println(hex); // ff0a141e

Как это устроено?

Класс встроенного системного класса java.math.BigInteger( java.math.BigInteger ) совместим с двоичными и шестнадцатеричными данными:

  • Он имеет конструктор BigInteger(signum=1, byte[])для создания большого целого числа byte[](установите его первый параметр signum= 1для правильной обработки отрицательных байтов)
  • Используйте BigInteger.toString(16)для преобразования большого целого числа в шестнадцатеричную строку
  • Для разбора шестнадцатеричного числа используйте new BigInteger("ffa74b", 16)- неправильно обрабатывает ведущий ноль

Если вы хотите иметь начальный ноль в шестнадцатеричном результате, проверьте его размер и добавьте недостающий ноль, если необходимо:

if (hex.length() % 2 == 1)
    hex = "0" + hex;

Ноты

Используйте new BigInteger(1, bytes)вместо new BigInteger(bytes), потому что Java « разбита по дизайну », и byteтип данных не содержит байтов, но подписан крошечными целыми числами [-128 ... 127]. Если первый байт отрицательный, BigIntegerпредполагается, что вы передаете отрицательное большое целое число. Просто передайте в 1качестве первого параметра ( signum=1).

Обратное преобразование из шестнадцатеричного формата вbyte[] хитрое: иногда в произведенный вывод входит ведущий ноль, и его следует очистить так:

byte[] bytes = new BigInteger("ffa74b", 16).toByteArray();
if (bytes[0] == 0) {
    byte[] newBytes = new byte[bytes.length - 1];
    System.arraycopy(bytes, 1, newBytes, 0, newBytes.length);
    bytes = newBytes;
}

Последнее замечание: если у byte[]него несколько ведущих нулей, они будут потеряны.


1
Если начальный байт имеет десятичное значение меньше 16, вы также получите строку с нечетным количеством шестнадцатеричных символов.
Алекс Йоргенсон

8

Если вы счастливы использовать внешнюю библиотеку, у org.apache.commons.codec.binary.Hexкласса есть encodeHexметод, который принимает byte[]и возвращает a char[]. Этот метод НАМНОГО быстрее, чем опция формата, и включает в себя детали преобразования. Также поставляется с decodeHexметодом для обратного преобразования.


4
Еще более простой способ - использовать встроенные функции javax.xml.bind.DatatypeConverter / parseHexBinary и printHexBinary. См. Stackoverflow.com/questions/9655181/…
Алан Томпсон

2
+1 к этой опции. Hex также имеет метод encodeHexString, который принимает byte [] и возвращает String.
Минцзян Ши

не забывайте, что javaxпространство имен не всегда доступно.
Мен

7

Вы можете использовать метод из библиотеки Bouncy Castle Provider :

org.bouncycastle.util.encoders.Hex.toHexString(byteArray);

Пакет Bouncy Castle Crypto представляет собой реализацию криптографических алгоритмов на Java. Этот jar содержит провайдера JCE и облегченный API для API криптографии Bouncy Castle для JDK 1.5 до JDK 1.8.

Maven зависимость:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.60</version>
</dependency>

или из кодека Apache Commons :

org.apache.commons.codec.binary.Hex.encodeHexString(byteArray);

Пакет кодеков Apache Commons содержит простой кодер и декодеры для различных форматов, таких как Base64 и Hexadecimal. В дополнение к этим широко используемым кодерам и декодерам пакет кодеков также поддерживает набор утилит фонетического кодирования.

Maven зависимость:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.11</version>
</dependency>

Да, это лучшее решение , но требуется внешняя библиотека: кодек Apache Commons ( mvnrepository.com/artifact/commons-codec/commons-codec/1.11 ) или поставщик BouncyCastle ( mvnrepository.com/artifact/org.bouncycastle/bcprov-). jdk15on / 1.60 )
Светлин Наков

5

Это код, который я нашел для запуска быстрее всего. Я запускал его на 109015 байтовых массивах длиной 32 в 23 мс. Я запускал его на виртуальной машине, так что, вероятно, он будет работать быстрее на голом металле.

public static final char[] HEX_DIGITS =         {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

public static char[] encodeHex( final byte[] data ){
    final int l = data.length;
    final char[] out = new char[l<<1];
    for( int i=0,j=0; i<l; i++ ){
        out[j++] = HEX_DIGITS[(0xF0 & data[i]) >>> 4];
        out[j++] = HEX_DIGITS[0x0F & data[i]];
    }
    return out;
}

Тогда вы можете просто сделать

String s = new String( encodeHex(myByteArray) );

3
BigInteger n = new BigInteger(byteArray);
String hexa = n.toString(16));

Не работает: BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)возвращается"-fdfcfbfb"
Martin Vysny

Это правильный результат. Вы работаете с байтами '-1', '2' ... '5'. То есть байты не имеют визуализации ( unicode.org ), если вы намерены работать с литералом '-1', '2' ... '5', вам следует работать со строковыми значениями.
Вендер

Это неправильный результат. Значение байта Java, равное -1, фактически равно 0xFF (так же, как (int) 255), поскольку байты Java подписаны, поэтому результат должен быть FF02030405. Если вы попробуете решение @Jerinaw выше, вы увидите, что оно выведет правильный вывод. Также см. Решение Светлина Накова ниже.
Мартин Высный

2

Вот простая функция для преобразования байта в шестнадцатеричный

   private static String convertToHex(byte[] data) {
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < data.length; i++) {
        int halfbyte = (data[i] >>> 4) & 0x0F;
        int two_halfs = 0;
        do {
            if ((0 <= halfbyte) && (halfbyte <= 9))
                buf.append((char) ('0' + halfbyte));
            else
                buf.append((char) ('a' + (halfbyte - 10)));
            halfbyte = data[i] & 0x0F;
        } while(two_halfs++ < 1);
    }
    return buf.toString();
}

2

Другие охватили общий случай. Но если у вас есть байтовый массив известной формы, например, MAC-адрес, то вы можете:

byte[] mac = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };

String str = String.format("%02X:%02X:%02X:%02X:%02X:%02X",
                           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 

1

Создание (и уничтожение) группы String экземпляров не является хорошим способом, если производительность является проблемой.

Пожалуйста, игнорируйте эти подробные (повторяющиеся) аргументы, проверяющие операторы if. Это для (других) образовательных целей.

Полный проект Maven: http://jinahya.googlecode.com/svn/trunk/com.googlecode.jinahya/hex-codec/

Кодирование ...

/**
 * Encodes a single nibble.
 *
 * @param decoded the nibble to encode.
 *
 * @return the encoded half octet.
 */
protected static int encodeHalf(final int decoded) {

    switch (decoded) {
        case 0x00:
        case 0x01:
        case 0x02:
        case 0x03:
        case 0x04:
        case 0x05:
        case 0x06:
        case 0x07:
        case 0x08:
        case 0x09:
            return decoded + 0x30; // 0x30('0') - 0x39('9')
        case 0x0A:
        case 0x0B:
        case 0x0C:
        case 0x0D:
        case 0x0E:
        case 0x0F:
            return decoded + 0x57; // 0x41('a') - 0x46('f')
        default:
            throw new IllegalArgumentException("illegal half: " + decoded);
    }
}


/**
 * Encodes a single octet into two nibbles.
 *
 * @param decoded the octet to encode.
 * @param encoded the array to which each encoded nibbles are written.
 * @param offset the offset in the array.
 */
protected static void encodeSingle(final int decoded, final byte[] encoded,
                                   final int offset) {

    if (encoded == null) {
        throw new IllegalArgumentException("null encoded");
    }

    if (encoded.length < 2) {
        // not required
        throw new IllegalArgumentException(
            "encoded.length(" + encoded.length + ") < 2");
    }

    if (offset < 0) {
        throw new IllegalArgumentException("offset(" + offset + ") < 0");
    }

    if (offset >= encoded.length - 1) {
        throw new IllegalArgumentException(
            "offset(" + offset + ") >= encoded.length(" + encoded.length
            + ") - 1");
    }

    encoded[offset] = (byte) encodeHalf((decoded >> 4) & 0x0F);
    encoded[offset + 1] = (byte) encodeHalf(decoded & 0x0F);
}


/**
 * Decodes given sequence of octets into a sequence of nibbles.
 *
 * @param decoded the octets to encode
 *
 * @return the encoded nibbles.
 */
protected static byte[] encodeMultiple(final byte[] decoded) {

    if (decoded == null) {
        throw new IllegalArgumentException("null decoded");
    }

    final byte[] encoded = new byte[decoded.length << 1];

    int offset = 0;
    for (int i = 0; i < decoded.length; i++) {
        encodeSingle(decoded[i], encoded, offset);
        offset += 2;
    }

    return encoded;
}


/**
 * Encodes given sequence of octets into a sequence of nibbles.
 *
 * @param decoded the octets to encode.
 *
 * @return the encoded nibbles.
 */
public byte[] encode(final byte[] decoded) {

    return encodeMultiple(decoded);
}

Декодирование ...

/**
 * Decodes a single nibble.
 *
 * @param encoded the nibble to decode.
 *
 * @return the decoded half octet.
 */
protected static int decodeHalf(final int encoded) {

    switch (encoded) {
        case 0x30: // '0'
        case 0x31: // '1'
        case 0x32: // '2'
        case 0x33: // '3'
        case 0x34: // '4'
        case 0x35: // '5'
        case 0x36: // '6'
        case 0x37: // '7'
        case 0x38: // '8'
        case 0x39: // '9'
            return encoded - 0x30;
        case 0x41: // 'A'
        case 0x42: // 'B'
        case 0x43: // 'C'
        case 0x44: // 'D'
        case 0x45: // 'E'
        case 0x46: // 'F'
            return encoded - 0x37;
        case 0x61: // 'a'
        case 0x62: // 'b'
        case 0x63: // 'c'
        case 0x64: // 'd'
        case 0x65: // 'e'
        case 0x66: // 'f'
            return encoded - 0x57;
        default:
            throw new IllegalArgumentException("illegal half: " + encoded);
    }
}


/**
 * Decodes two nibbles into a single octet.
 *
 * @param encoded the nibble array.
 * @param offset the offset in the array.
 *
 * @return decoded octet.
 */
protected static int decodeSingle(final byte[] encoded, final int offset) {

    if (encoded == null) {
        throw new IllegalArgumentException("null encoded");
    }

    if (encoded.length < 2) {
        // not required
        throw new IllegalArgumentException(
            "encoded.length(" + encoded.length + ") < 2");
    }

    if (offset < 0) {
        throw new IllegalArgumentException("offset(" + offset + ") < 0");
    }

    if (offset >= encoded.length - 1) {
        throw new IllegalArgumentException(
            "offset(" + offset + ") >= encoded.length(" + encoded.length
            + ") - 1");
    }

    return (decodeHalf(encoded[offset]) << 4)
           | decodeHalf(encoded[offset + 1]);
}


/**
 * Encodes given sequence of nibbles into a sequence of octets.
 *
 * @param encoded the nibbles to decode.
 *
 * @return the encoded octets.
 */
protected static byte[] decodeMultiple(final byte[] encoded) {

    if (encoded == null) {
        throw new IllegalArgumentException("null encoded");
    }

    if ((encoded.length & 0x01) == 0x01) {
        throw new IllegalArgumentException(
            "encoded.length(" + encoded.length + ") is not even");
    }

    final byte[] decoded = new byte[encoded.length >> 1];

    int offset = 0;
    for (int i = 0; i < decoded.length; i++) {
        decoded[i] = (byte) decodeSingle(encoded, offset);
        offset += 2;
    }

    return decoded;
}


/**
 * Decodes given sequence of nibbles into a sequence of octets.
 *
 * @param encoded the nibbles to decode.
 *
 * @return the decoded octets.
 */
public byte[] decode(final byte[] encoded) {

    return decodeMultiple(encoded);
}

1

Это очень быстрый способ. Внешние библиотеки не нужны.

final protected static char[] HEXARRAY = "0123456789abcdef".toCharArray();

    public static String encodeHexString( 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] = HEXARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEXARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }

1

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

Integer intValue = 149;

Соответствующее значение байта:

Byte byteValue = intValue.byteValue(); // this will convert the rightmost byte of the intValue to byte, because Byte is an 8 bit object and Integer is at least 16 bit, and it will give you a signed number in this case -107

получить целочисленное значение из байтовой переменной:

Integer anInt = byteValue.intValue(); // This will convert the byteValue variable to a signed Integer

От байта и целого до шестнадцатеричной строки:
так я делаю:

Integer anInt = 149
Byte aByte = anInt.byteValue();

String hexFromInt = "".format("0x%x", anInt); // This will output 0x95
String hexFromByte = "".format("0x%x", aByte); // This will output 0x95

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

От байта [] к строке:

    public static String byteArrayToHexString(byte[] byteArray){
        String hexString = "";

        for(int i = 0; i < byteArray.length; i++){
            String thisByte = "".format("%x", byteArray[i]);
            hexString += thisByte;
        }

        return hexString;
    }

И из шестнадцатеричной строки в байт []:

public static byte[] hexStringToByteArray(String hexString){
    byte[] bytes = new byte[hexString.length() / 2];

    for(int i = 0; i < hexString.length(); i += 2){
        String sub = hexString.substring(i, i + 2);
        Integer intVal = Integer.parseInt(sub, 16);
        bytes[i / 2] = intVal.byteValue();
        String hex = "".format("0x%x", bytes[i / 2]);
    }

    return bytes;
}  

Слишком поздно, но я надеюсь, что это может помочь другим;)


1

Вот ваш быстрый метод:

    private static final String[] hexes = 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 hexes[b&0xFF];
    }

1
некрасиво, но, вероятно, очень эффективно. :-)
Rich S

1

Как и некоторые другие ответы, я рекомендую использовать String.format()и BigInteger. Но для интерпретации байтового массива как двоичного представления с прямым порядком байтов вместо двоичного представления с двумя дополнительными значениями (с сигнумом и неполным использованием диапазона возможных шестнадцатеричных значений) используйте BigInteger (int signum, byte [] magnitude) , а не BigInteger (byte [] val ) .

Например, для байтового массива длиной 8 используйте:

String.format("%016X", new BigInteger(1,bytes))

Преимущества:

  • ведущие нули
  • нет подписи
  • только встроенные функции
  • только одна строка кода

Недостаток:

  • Там могут быть более эффективные способы сделать это

Пример:

byte[] bytes = new byte[8];
Random r = new Random();
System.out.println("big-endian       | two's-complement");
System.out.println("-----------------|-----------------");
for (int i = 0; i < 10; i++) {
    r.nextBytes(bytes);
    System.out.print(String.format("%016X", new BigInteger(1,bytes)));
    System.out.print(" | ");
    System.out.print(String.format("%016X", new BigInteger(bytes)));
    System.out.println();
}

Пример вывода:

big-endian       | two's-complement
-----------------|-----------------
3971B56BC7C80590 | 3971B56BC7C80590
64D3C133C86CCBDC | 64D3C133C86CCBDC
B232EFD5BC40FA61 | -4DCD102A43BF059F
CD350CC7DF7C9731 | -32CAF338208368CF
82CDC9ECC1BC8EED | -7D3236133E437113
F438C8C34911A7F5 | -BC7373CB6EE580B
5E99738BE6ACE798 | 5E99738BE6ACE798
A565FE5CE43AA8DD | -5A9A01A31BC55723
032EBA783D2E9A9F | 032EBA783D2E9A9F
8FDAA07263217ABA | -70255F8D9CDE8546

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.