Преобразовать строковое представление шестнадцатеричного дампа в массив байтов с помощью Java?

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

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

Но чтобы сохранить оригинальность, я сформулирую это по-своему: предположим, у меня есть строка "00A0BF", которую я хотел бы интерпретировать как

byte[] {0x00,0xA0,0xBf}

Что я должен делать?

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

См. Также stackoverflow.com/questions/9655181/….

flow2k 23.10.2018 21:54

Приручил BigIntegerздесь.

John McClane 25.11.2018 04:34

FWIW String.getBytes() не будет работать так, как вы думаете. Пришлось усвоить это на собственном горьком опыте. if ("FF".getBytes() != "ff".getBytes()) { System.out.println("Try again"); }

tir38 11.09.2019 20:05
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
393
3
499 542
24
Перейти к ответу Данный вопрос помечен как решенный

Ответы 24

Класс Hex в commons-codec должен сделать это за вас.

http://commons.apache.org/codec/

import org.apache.commons.codec.binary.Hex;
...
byte[] decoded = Hex.decodeHex("00A0BF");
// 0x00 0xA0 0xBF

Это тоже хорошо выглядит. См. Org.apache.commons.codec.binary.Hex.decodeHex ()

Dave L. 26.09.2008 21:46

Это было интересно. Но мне было трудно следовать их решению. Есть ли у него какие-либо преимущества по сравнению с тем, что вы предложили (кроме проверки четного количества символов)?

rafraf 27.09.2008 05:06

Я всегда использовал такой метод, как

public static final byte[] fromHexString(final String s) {
    String[] v = s.split(" ");
    byte[] arr = new byte[v.length];
    int i = 0;
    for(String val: v) {
        arr[i++] =  Integer.decode("0x" + val).byteValue();

    }
    return arr;
}

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

Конкатенация строк не требуется. Просто используйте Integer.valueOf (val, 16).

Michael Myers 26.09.2008 19:21

Я пробовал использовать такие преобразования системы счисления раньше, и у меня были смешанные результаты

pfranza 26.09.2008 19:23

спасибо - как ни странно, он отлично работает с этой строкой: «9C001C» или «001C21» и не работает с этой: «9C001C21» Исключение в потоке «main» java.lang.NumberFormatException: для входной строки: «9C001C21» на java.lang. NumberFormatException.forInputString (неизвестный источник)

rafraf 26.09.2008 20:07

(Это не более странно, чем в случае Byte / byte: старший бит установлен без начала -)

greybeard 13.02.2016 21:17

Думаю сделаю это за тебя. Я собрал его из аналогичной функции, которая возвращала данные в виде строки:

private static byte[] decode(String encoded) {
    byte result[] = new byte[encoded/2];
    char enc[] = encoded.toUpperCase().toCharArray();
    StringBuffer curr;
    for (int i = 0; i < enc.length; i += 2) {
        curr = new StringBuffer("");
        curr.append(String.valueOf(enc[i]));
        curr.append(String.valueOf(enc[i + 1]));
        result[i] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    return result;
}

Во-первых, вам не нужно преобразовывать строку в верхний регистр. Во-вторых, можно добавлять символы непосредственно в StringBuffer, что должно быть намного эффективнее.

Michael Myers 26.09.2008 19:48

Обновлено: как указано @mmyers, этот метод не работает с вводом, который содержит подстроки, соответствующие байтам с установленным старшим битом («80» - «FF»). Объяснение находится в Идентификатор ошибки: 6259307 Byte.parseByte не работает, как указано в документации SDK.

public static final byte[] fromHexString(final String s) {
    byte[] arr = new byte[s.length()/2];
    for ( int start = 0; start < s.length(); start += 2 )
    {
        String thisByte = s.substring(start, start+2);
        arr[start/2] = Byte.parseByte(thisByte, 16);
    }
    return arr;
}

Закрыть, но этот метод не работает на данном входе "00A0BBF". См. bugs.sun.com/bugdatabase/view_bug.do?bug_id=6259307.

Michael Myers 26.09.2008 19:34

Также как ни странно это не касается «9С».

rafraf 26.09.2008 19:58

@mmyers: эй. Это не хорошо. Извините за путаницу. @ravigad: 9C имеет ту же проблему, потому что в этом случае установлен старший бит.

Blair Conrad 26.09.2008 20:37

(byte) Short.parseShort (thisByte, 16) решает эту проблему

Jamey Hicks 28.07.2017 16:10

Вот метод, который действительно работает (на основе нескольких предыдущих полуправильных ответов):

private static byte[] fromHexString(final String encoded) {
    if ((encoded.length() % 2) != 0)
        throw new IllegalArgumentException("Input string must contain an even number of characters");

    final byte result[] = new byte[encoded.length()/2];
    final char enc[] = encoded.toCharArray();
    for (int i = 0; i < enc.length; i += 2) {
        StringBuilder curr = new StringBuilder(2);
        curr.append(enc[i]).append(enc[i + 1]);
        result[i/2] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    return result;
}

Единственная возможная проблема, которую я вижу, - слишком длинная входная строка; вызов toCharArray () делает копию внутреннего массива строки.

Обновлено: Да, кстати, байты подписаны в Java, поэтому ваша входная строка преобразуется в [0, -96, -65] вместо [0, 160, 191]. Но вы, наверное, это уже знали.

Спасибо, Майкл - ты спасатель! Работа над проектом BlackBerry и попытка преобразовать строковое представление байта обратно в байт ... с помощью метода RIM «Byte.parseByte (byteString, 16)». Продолжал бросать NumberFormatExcpetion. Потратил часы, пытаясь понять, почему. Ваше предложение «Integer.praseInt ()» помогло. Еще раз спасибо!!

BonanzaDriver 23.10.2011 23:28

На самом деле, я думаю, что BigInteger - это очень хорошее решение:

new BigInteger("00A0BF", 16).toByteArray();

Обновлено: Небезопасно для ведущих нулей, как отмечено на плакате.

Я тоже так думал изначально. И спасибо за документирование - я просто подумал, что должен ... он делал некоторые странные вещи, хотя я действительно не понимал - например, опускал некоторые ведущие 0x00, а также смешивал порядок 1 байта в строке из 156 байтов. играл с.

rafraf 26.09.2008 20:43

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

Dave L. 26.09.2008 20:55

да, как только я это сказал, я тоже не поверил :) Я провел сравнение байтового массива из BigInteger с mmyers'fromHexString и (без 0x00) с ошибочной строкой - они были идентичны. «Путаница» действительно произошла, но могло быть что-то еще. Я посмотрю повнимательнее завтра

rafraf 26.09.2008 21:09

Проблема с BigInteger в том, что должен быть «знаковый бит». Если в ведущем байте установлен старший бит, то результирующий массив байтов имеет дополнительный 0 в 1-й позиции. Но все же +1.

Gray 28.10.2011 20:20
Ответ принят как подходящий

Вот решение, которое, на мой взгляд, лучше, чем все опубликованные до сих пор:

/* s must be an even-length string. */
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;
}

Причины улучшения:

  • Безопасно с ведущими нулями (в отличие от BigInteger) и с отрицательными байтовыми значениями (в отличие от Byte.parseByte)

  • Не преобразует String в char[] и не создает объекты StringBuilder и String для каждого байта.

  • Нет зависимостей библиотеки, которые могут быть недоступны

Не стесняйтесь добавлять проверку аргументов через assert или исключения, если известно, что аргумент небезопасен.

Спасибо. Для этого должен быть встроенный. Тем более, что Byte.parseByte хрипит на отрицательных значениях громоздко.

Thilo 14.03.2010 14:02

Дает неверный результат. См. Реализацию apache в сообщении ниже.

Gabriel Llamas 16.04.2011 16:04

Можете ли вы привести пример, который неправильно декодирован, или объясните, в чем его ошибка?

Dave L. 17.04.2011 18:35

Это не работает для строки «0». Выдает исключение java.lang.StringIndexOutOfBoundsException

ovdsrn 09.06.2011 00:06

«0» - недопустимый ввод. Для каждого байта требуется две шестнадцатеричные цифры. Как отмечается в ответе: «Не стесняйтесь добавлять проверку аргумента ... если известно, что аргумент небезопасен».

Dave L. 09.06.2011 20:42

javax.xml.bind.DatatypeConverter.parseHexBinary (hexString) кажется примерно на 20% быстрее, чем вышеупомянутое решение в моих микротестах (независимо от того, сколько они стоят), а также правильно выбрасывает исключения при недопустимом вводе (например, "gg" не является допустимым hexString, но вернет -77, используя предложенное решение).

Trevor Freeman 04.04.2012 22:31

Я не понимаю этого: безопасно с ведущими нулями (в отличие от BigInteger) и с отрицательными байтовыми значениями (в отличие от Byte.parseByte), насколько эти два небезопасны? Не могли бы вы привести примеры для тестирования?

Muhammad Annaqeeb 19.03.2014 18:29

@MuhammadAnnaqeeb См. Другие ответы ниже, в которых используется BigInteger или Byte.parseByte.

Dave L. 19.03.2014 22:03

@Dave Разве здесь не должен использоваться логический сдвиг вместо арифметического?

Chef Pharaoh 22.10.2014 23:44

@ChefPharaoh В Java есть только один оператор сдвига влево, который имеет тот же эффект, что и логический или арифметический сдвиг. См. en.wikipedia.org/wiki/Logical_shift

Dave L. 23.10.2014 03:06

Как выглядит шестнадцатеричный дамп. Кто-нибудь может привести пример

Arun George 23.01.2015 01:57

Мне интересно, может ли data[i / 2] = (byte) (((Character.digit(s.charAt(i), 16) << 4) | Character.digit(s.charAt(i + 1), 16))); быть чуть более оптимальным? Или может потребоваться маска 0xFF.

Brett Ryan 20.02.2015 10:54

Если оператор for изменен на for (int i = 0; i < len - 1; i += 2), функция больше не будет генерировать исключения для данных недопустимой длины. В этих случаях он все равно не вернет правильные данные, но, по крайней мере, сбой больше не будет.

DaedalusAlpha 13.05.2015 14:22

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

Dave L. 17.06.2015 19:03

Работает как шарм. Для индекса, выходящего за границы, введите шестнадцатеричную строку префикса с «0», чтобы сделать строку любого размера, который вам нужен для вывода - например, если вы конвертируете двухбайтовую шестнадцатеричную строку, сделайте это перед вызовом метода StringUtils .leftPad (hextString, 4, «0»). Два символа в шестнадцатеричной строке преобразуются в 1 байт.

Rohan 11.12.2015 04:25

Я добавил причину ... при разработке для android / linux / windows / macosx / ios в одной исходной базе это решение всегда работает.

Erik Aronesty 24.07.2018 23:02

Я категорически не согласен с тем, что «0 - недопустимый ввод». 0 - это вполне допустимая шестнадцатеричная строка. Тот факт, что это небезопасно для этого кода, не означает, что он недействителен. Тот факт, что каждый байт обычно выражается двумя шестнадцатеричными символами, не означает, что 0 не является допустимой шестнадцатеричной строкой; шестнадцатеричные строки могут быть преобразованы во многие вещи помимо байтовых массивов. Если функция требует в качестве входных данных шестнадцатеричную строку четной длины, это следует четко задокументировать, вместо того, чтобы оставлять пользователю возможность анализировать код, чтобы узнать, каковы его предположения. garethrees.org/2014/05/08/heartbleed

LarsH 04.08.2020 21:55

@LarsH Спасибо за напоминание о том, что всегда хорошо четко выражать свои предположения. В контексте этого вопроса о шестнадцатеричном дампе с примером использования пар символов, включая ведущие нули, я считаю справедливым предположение, что данные должны представлять байты с использованием двух символов каждый. Однако я могу представить себе домены, в которых можно было бы разрешить вместо этого особый случай одиночного или ведущего символа «0». Я согласен с тем, что если эта функция является частью общедоступного API, это поведение в любом случае должно быть задокументировано, как в org.apache.commons.codec.binary.Hex и типах данных XML.

Dave L. 05.08.2020 01:21

Справедливо. В заголовке вопроса написано «шестнадцатеричный дамп», а не просто «шестнадцатеричная строка». Кстати, я просто использовал ваш код в производственном проекте. (И добавил проверку для строк нечетной длины.) Так что спасибо.

LarsH 05.08.2020 18:46

P.S. Я внес предлагаемую правку, чтобы задокументировать это предположение. Очевидно, вы можете изменить его по своему желанию.

LarsH 05.08.2020 19:04

104207194088 TESTINGG 4304 GG2741 ��ôCONN��� | �� $ GK23000023R00P08TESTINGG1042071940882010260720‌ 03BVodafone IN�������������; �� -> Получение "??" тип ответа при получении данных через сокет дейтаграммы. Любое предложение, где я ошибаюсь?

Bhavin Chauhan 26.10.2020 10:21

Метод BigInteger() из java.math очень медленный и не рекомендуется.

Integer.parseInt(HEXString, 16)

может вызвать проблемы с некоторыми персонажами без преобразование в цифру / целое число

Хороший рабочий метод:

Integer.decode("0xXX") .byteValue()

Функция:

public static byte[] HexStringToByteArray(String s) {
    byte data[] = new byte[s.length()/2];
    for(int i=0;i < s.length();i+=2) {
        data[i/2] = (Integer.decode("0x"+s.charAt(i)+s.charAt(i+1))).byteValue();
    }
    return data;
}

Удачи, удачи

public static byte[] hex2ba(String sHex) throws Hex2baException {
    if (1==sHex.length()%2) {
        throw(new Hex2baException("Hex string need even number of chars"));
    }

    byte[] ba = new byte[sHex.length()/2];
    for (int i=0;i<sHex.length()/2;i++) {
        ba[i] = (Integer.decode(
                "0x"+sHex.substring(i*2, (i+1)*2))).byteValue();
    }
    return ba;
}

Мне нравится решение Character.digit, но вот как я его решил

public byte[] hex2ByteArray( String hexString ) {
    String hexVal = "0123456789ABCDEF";
    byte[] out = new byte[hexString.length() / 2];

    int n = hexString.length();

    for( int i = 0; i < n; i += 2 ) {
        //make a bit representation in an int of the hex value 
        int hn = hexVal.indexOf( hexString.charAt( i ) );
        int ln = hexVal.indexOf( hexString.charAt( i + 1 ) );

        //now just shift the high order nibble and add them together
        out[i/2] = (byte)( ( hn << 4 ) | ln );
    }

    return out;
}

HexBinaryAdapter обеспечивает возможность упорядочивания и отмены маршалинга между String и byte[].

import javax.xml.bind.annotation.adapters.HexBinaryAdapter;

public byte[] hexToBytes(String hexString) {
     HexBinaryAdapter adapter = new HexBinaryAdapter();
     byte[] bytes = adapter.unmarshal(hexString);
     return bytes;
}

Это просто пример, который я ввел ... Я просто использую его как есть, и мне не нужно создавать отдельный метод для его использования.

Он работает, только если входная строка (hexString) имеет четное количество символов. В противном случае: исключение в потоке «main» java.lang.IllegalArgumentException: hexBinary должен быть четной длины:

ovdsrn 09.06.2011 00:15

О, спасибо, что указали на это. У пользователя действительно не должно быть нечетного количества символов, потому что массив байтов представлен как {0x00,0xA0,0xBf}. Каждый байт состоит из двух шестнадцатеричных цифр или полубайта. Таким образом, любое количество байтов всегда должно содержать четное количество символов. Спасибо, что упомянули об этом.

GrkEngineer 16.06.2011 19:54

Вы можете использовать java.xml.bind.DatatypeConverter.parseHexBinary (hexString) напрямую вместо использования HexBinaryAdapter (который, в свою очередь, вызывает DatatypeConverter). Таким образом, вам не нужно создавать объект экземпляра адаптера (поскольку методы DatatypeConverter статичны).

Trevor Freeman 04.04.2012 22:33

javax.xml.bind. * больше не доступен в Java 9. Опасно то, что код, использующий его, будет компилироваться под Java 1.8 или более ранней версии (Java 9 с исходными настройками до более ранней версии), но получит исключение времени выполнения, работающее под Java 9.

Stephen M -on strike- 28.08.2017 19:52

Однострочные:

import javax.xml.bind.DatatypeConverter;

public static String toHexString(byte[] array) {
    return DatatypeConverter.printHexBinary(array);
}

public static byte[] toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s);
}

Предупреждения:

  • в Java 9 Jigsaw это больше не является частью (по умолчанию) корня java.se установить так, что это приведет к исключению ClassNotFoundException, если вы не укажете --add-modules java.se.ee (спасибо @ eckes)
  • Недоступно на Android (спасибо Fabian за это), но вы можете просто взять исходный код, если в вашей системе по какой-то причине отсутствует javax.xml. Спасибо @ Bert Regelink за извлечение исходного кода.

IMHO, это должен быть принятый / лучший ответ, поскольку он короткий и чистить (в отличие от ответа @DaveL) и не требует каких-либо внешних библиотек (например, ответ skaffman). Также <Введите старый анекдот об изобретении велосипеда>.

Priidu Neemre 18.08.2015 15:40

например, класс datatypeconverter недоступен в Android.

Fabian 10.02.2016 15:41

Предупреждение: в Java 9 Jigsaw это больше не является частью (по умолчанию) корневого набора java.se, поэтому результатом будет ClassNotFoundException, если вы не укажете --add-modules java.se.ee.

eckes 10.11.2016 15:17

Удивительный ответ, мог декодировать строковый запрос base64, использовать шестнадцатеричный для преобразования массива байтов с предоставленным решением, и он работал как шарм

dantebarba 06.01.2017 22:20

@dantebarba Я думаю, что javax.xml.bind.DatatypeConverter уже предоставляет метод кодирования / декодирования данных Base64. См. parseBase64Binary() и printBase64Binary().

DragShot 04.07.2017 01:18

может подтвердить, что в зависимости от javax.xml.bind может вызвать java.lang.NoClassDefFoundError.

Dmitry 15.05.2018 01:40

Чтобы добавить к проблемам с DataTypeConverter, Java SE 11 полностью удалил JAXB API и теперь включен только в Java EE. Вы также можете добавить его как зависимость Maven, как предлагается здесь: stackoverflow.com/a/43574427/7347751

David Mordigal 30.01.2019 08:51

Я нашел Kernel Panic как наиболее полезное для меня решение, но столкнулся с проблемами, если шестнадцатеричная строка была нечетным числом. решил это так:

boolean isOdd(int value)
{
    return (value & 0x01) !=0;
}

private int hexToByte(byte[] out, int value)
{
    String hexVal = "0123456789ABCDEF"; 
    String hexValL = "0123456789abcdef";
    String st = Integer.toHexString(value);
    int len = st.length();
    if (isOdd(len))
        {
        len+=1; // need length to be an even number.
        st = ("0" + st);  // make it an even number of chars
        }
    out[0]=(byte)(len/2);
    for (int i =0;i<len;i+=2)
    {
        int hh = hexVal.indexOf(st.charAt(i));
            if (hh == -1)  hh = hexValL.indexOf(st.charAt(i));
        int lh = hexVal.indexOf(st.charAt(i+1));
            if (lh == -1)  lh = hexValL.indexOf(st.charAt(i+1));
        out[(i/2)+1] = (byte)((hh << 4)|lh);
    }
    return (len/2)+1;
}

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

One-liners:

import javax.xml.bind.DatatypeConverter;

public static String toHexString(byte[] array) {
    return DatatypeConverter.printHexBinary(array);
}

public static byte[] toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s);
}

Для тех из вас, кто интересуется фактическим кодом Однострочные из FractalizeR (мне это нужно, поскольку javax.xml.bind недоступен для Android (по умолчанию)), это исходит из com.sun.xml.internal.bind.DatatypeConverterImpl.java:

public byte[] parseHexBinary(String s) {
    final int len = s.length();

    // "111" is not a valid hex encoding.
    if ( len%2 != 0 )
        throw new IllegalArgumentException("hexBinary needs to be even-length: "+s);

    byte[] out = new byte[len/2];

    for( int i=0; i<len; i+=2 ) {
        int h = hexToBin(s.charAt(i  ));
        int l = hexToBin(s.charAt(i+1));
        if ( h==-1 || l==-1 )
            throw new IllegalArgumentException("contains illegal character for hexBinary: "+s);

        out[i/2] = (byte)(h*16+l);
    }

    return out;
}

private static int hexToBin( 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 char[] hexCode = "0123456789ABCDEF".toCharArray();

public String printHexBinary(byte[] data) {
    StringBuilder r = new StringBuilder(data.length*2);
    for ( byte b : data) {
        r.append(hexCode[(b >> 4) & 0xF]);
        r.append(hexCode[(b & 0xF)]);
    }
    return r.toString();
}

DatatypeConverter также по умолчанию недоступен в Java 9. Опасно то, что код, использующий его, будет компилироваться под Java 1.8 или более ранней версии (Java 9 с исходными настройками до более ранней версии), но получит исключение времени выполнения под Java 9 без "--add-modules java.se.ee".

Stephen M -on strike- 28.08.2017 19:54

Кодекс, представленный Бертом Регелинком, просто не работает. Попробуйте следующее:

import javax.xml.bind.DatatypeConverter;
import java.io.*;

public class Test
{  
    @Test
    public void testObjectStreams( ) throws IOException, ClassNotFoundException
    {     
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);

            String stringTest = "TEST";
            oos.writeObject( stringTest );

            oos.close();
            baos.close();

            byte[] bytes = baos.toByteArray();
            String hexString = DatatypeConverter.printHexBinary( bytes);
            byte[] reconvertedBytes = DatatypeConverter.parseHexBinary(hexString);

            assertArrayEquals( bytes, reconvertedBytes );

            ByteArrayInputStream bais = new ByteArrayInputStream(reconvertedBytes);
            ObjectInputStream ois = new ObjectInputStream(bais);

            String readString = (String) ois.readObject();

            assertEquals( stringTest, readString);
        }
    }

На самом деле это другая проблема и, вероятно, принадлежит к другому потоку.

Sean Coffey 08.11.2012 23:48

Теперь для этого можно использовать BaseEncoding в guava.

BaseEncoding.base16().decode(string);

Чтобы изменить это, используйте

BaseEncoding.base16().encode(bytes);

Основываясь на предложенном решении, следующее должно быть немного более эффективным:

  public static byte [] hexStringToByteArray (final String s) {
    if (s == null || (s.length () % 2) == 1)
      throw new IllegalArgumentException ();
    final char [] chars = s.toCharArray ();
    final int len = chars.length;
    final byte [] data = new byte [len / 2];
    for (int i = 0; i < len; i += 2) {
      data[i / 2] = (byte) ((Character.digit (chars[i], 16) << 4) + Character.digit (chars[i + 1], 16));
    }
    return data;
  }

Потому что: первоначальное преобразование в массив символов избавляет от проверки длины в charAt

Для меня это было решение, HEX = "FF01" затем разделить на FF (255) и 01 (01)

private static byte[] BytesEncode(String encoded) {
    //System.out.println(encoded.length());
    byte result[] = new byte[encoded.length() / 2];
    char enc[] = encoded.toUpperCase().toCharArray();
    String curr = "";
    for (int i = 0; i < encoded.length(); i=i+2) {
        curr = encoded.substring(i,i+2);
        System.out.println(curr);
        if (i==0){
            result[i]=((byte) Integer.parseInt(curr, 16));
        }else{
            result[i/2]=((byte) Integer.parseInt(curr, 16));
        }

    }
    return result;
}

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

rfornal 06.12.2014 04:10

В android, если вы работаете с hex, можете попробовать окио.

простое использование:

byte[] bytes = ByteString.decodeHex("c000060000").toByteArray();

и результат будет

[-64, 0, 6, 0, 0]

Я тестировал много разных методов, но этот как минимум в два раза быстрее!

poby 05.05.2020 09:07

Вот еще одна версия, которая поддерживает строки нечетной длины, не прибегая к конкатенации строк.

public static byte[] hexStringToByteArray(String input) {
    int len = input.length();

    if (len == 0) {
        return new byte[] {};
    }

    byte[] data;
    int startIdx;
    if (len % 2 != 0) {
        data = new byte[(len / 2) + 1];
        data[0] = (byte) Character.digit(input.charAt(0), 16);
        startIdx = 1;
    } else {
        data = new byte[len / 2];
        startIdx = 0;
    }

    for (int i = startIdx; i < len; i += 2) {
        data[(i + 1) / 2] = (byte) ((Character.digit(input.charAt(i), 16) << 4)
                + Character.digit(input.charAt(i+1), 16));
    }
    return data;
}

Мое формальное решение:

/**
 * Decodes a hexadecimally encoded binary string.
 * <p>
 * Note that this function does <em>NOT</em> convert a hexadecimal number to a
 * binary number.
 *
 * @param hex Hexadecimal representation of data.
 * @return The byte[] representation of the given data.
 * @throws NumberFormatException If the hexadecimal input string is of odd
 * length or invalid hexadecimal string.
 */
public static byte[] hex2bin(String hex) throws NumberFormatException {
    if (hex.length() % 2 > 0) {
        throw new NumberFormatException("Hexadecimal input string must have an even length.");
    }
    byte[] r = new byte[hex.length() / 2];
    for (int i = hex.length(); i > 0;) {
        r[i / 2 - 1] = (byte) (digit(hex.charAt(--i)) | (digit(hex.charAt(--i)) << 4));
    }
    return r;
}

private static int digit(char ch) {
    int r = Character.digit(ch, 16);
    if (r < 0) {
        throw new NumberFormatException("Invalid hexadecimal string: " + ch);
    }
    return r;
}

Похож на Функция PHP hex2bin (), но в стиле Java.

Пример:

String data = new String(hex2bin("6578616d706c65206865782064617461"));
// data value: "example hex data"

Если вы предпочитаете потоки Java 8 в качестве стиля кодирования, этого можно достичь, используя только примитивы JDK.

String hex = "0001027f80fdfeff";

byte[] converted = IntStream.range(0, hex.length() / 2)
    .map(i -> Character.digit(hex.charAt(i * 2), 16) << 4 | Character.digit(hex.charAt((i * 2) + 1), 16))
    .collect(ByteArrayOutputStream::new,
             ByteArrayOutputStream::write,
             (s1, s2) -> s1.write(s2.toByteArray(), 0, s2.size()))
    .toByteArray();

Параметры , 0, s2.size() в функции конкатенации сборщика могут быть опущены, если вы не против перехвата IOException.

Поздно к вечеринке, но я объединил приведенный выше ответ DaveL в класс с обратным действием - на всякий случай, это помогает.

public final class HexString {
    private static final char[] digits = "0123456789ABCDEF".toCharArray();

    private HexString() {}

    public static final String fromBytes(final byte[] bytes) {
        final StringBuilder buf = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            buf.append(HexString.digits[(bytes[i] >> 4) & 0x0f]);
            buf.append(HexString.digits[bytes[i] & 0x0f]);
        }
        return buf.toString();
    }

    public static final byte[] toByteArray(final String hexString) {
        if ((hexString.length() % 2) != 0) {
            throw new IllegalArgumentException("Input string must contain an even number of characters");
        }
        final int len = hexString.length();
        final byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        return data;
    }
}

И тестовый класс JUnit:

public class TestHexString {

    @Test
    public void test() {
        String[] tests = {"0FA1056D73", "", "00", "0123456789ABCDEF", "FFFFFFFF"};

        for (int i = 0; i < tests.length; i++) {
            String in = tests[i];
            byte[] bytes = HexString.toByteArray(in);
            String out = HexString.fromBytes(bytes);
            System.out.println(in); //DEBUG
            System.out.println(out); //DEBUG
            Assert.assertEquals(in, out);

        }

    }

}

Я знаю, что это очень старая ветка, но все же хочу добавить свою копейку.

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

public static byte[] hexToBinary(String s){

  /*
   * skipped any input validation code
   */

  byte[] data = new byte[s.length()/2];

  for( int i=0, j=0; 
       i<s.length() && j<data.length; 
       i+=2, j++)
  {
     data[j] = (byte)Integer.parseInt(s.substring(i, i+2), 16);
  }

  return data;
}

Другие вопросы по теме