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

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

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

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 заключается в том, что она не toHexString нулями:

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

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

Рекомендации

  • JLS 4.2.1 Интегральные типы и значения
    • Для byte от -128 до 127 включительно
  • JLS 5.1.2 Расширение примитивного преобразования

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

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

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

Что это значит? Несколько вещей: во-первых, и самое главное, это означает, что мы работаем с 8-битами . Так, например, мы можем записать номер 2 как 0000 0010. Однако, поскольку это дополнение к двум, мы пишем отрицательный 2 следующим образом: 1111 1110. Что также означает, что преобразование в hex очень просто. То есть вы просто конвертируете каждый 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 (в дополнение к двум) в Hex.

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) Теперь преобразуем в шестнадцатеричный:

 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 он представлен как дополнение 2xFFFFFFFF!

Поэтому вернемся к нашему примеру:

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

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

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

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

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

 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() , String.format() является правильным ответом по сравнению с Integer.toHexString() (поскольку он имеет дело с отрицательными числами правильным образом).

Лучшее решение – это один лайнер:

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

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

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

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

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

Это код, который, как я нашел, работает быстрее всего. Я запустил его на 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>> 4]; out[j++] = HEX_DIGITS[0x0F & data[i]]; } return out; } 

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

 String s = new String( encodeHex(myByteArray) ); 
 BigInteger n = new BigInteger(byteArray); String hexa = n.toString(16)); 
 org.bouncycastle.util.encoders.Hex.toHexString(byteArray); 

или

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

Другие рассмотрели общий случай. Но если у вас есть массив байтов известной формы, например 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]); 

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

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

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

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

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

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

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

Полный проект 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); } 

Это очень быстрый способ. Никаких внешних библиотек не требуется.

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

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

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

использование

 Integer.toHexString((int)b); 
  • Как получить первый день текущей недели и месяца?
  • Динамические имена переменных Java
  • Что такое обратный вызов в Android?
  • java.lang.ClassNotFoundException: Не нашел class на пути: dexpathlist
  • АБР по беспроводной сети
  • Не удалось войти в систему. Проверьте подключение к сети и повторите попытку.
  • RxJava вместо AsyncTask?
  • Перезапустите службу, даже если приложение отключено и продолжает работать в фоновом режиме даже после закрытия приложения How?
  • Android AudioRecord class - быстро запускает живой микрофон, настраивает функцию обратного вызова
  • Java: как получить входные данные из System.console ()
  • Преобразование UTC в текущее время локали
  • Давайте будем гением компьютера.