Як перетворити масив байтів у шістнадцяткову рядок на Java?


649

У мене є байтовий масив, наповнений шістнадцятковими номерами, і надрукувати його простий спосіб досить безглуздо, оскільки є безліч недрукованих елементів. Що мені потрібно - це точний гек-код у вигляді:3a5f771c


12
Чому б просто не спробувати спершу і показати нам, що у вас є. Ви нічого не втрачаєте і все набираєте. У Integer є toHexString(...)метод, який може допомогти, якщо це те, що ви шукаєте. Також String.format(...)можна виконати кілька акуратних прийомів форматування, використовуючи %2xрядок коду.
Hovercraft Full Of Eels


"Мені потрібно точний гек-код у вигляді: 3a5f771c ..." - ви запитали точну форму, але ви не вказали точного прикладу. Перейшовши на те, що ви надали, перетворіть перші чотири байти в рядок, а потім з'єднайте еліпси в рядок.
jww

1
За допомогою потоку в Java 8 його можна просто реалізувати як: статичний String byteArrayToHex (byte [] a) {return IntStream.range (0, a.length) .mapToObj (i -> String.format ("% 02x ", a [i])) .reduce ((acc, v) -> acc +" "+ v) .get (); }
tibetty

Відповіді:


900

З обговорення тут , і особливо цієї відповіді, це функція, яку я зараз використовую:

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 Codec, який використовує дуже схожий код.)

Версія 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Використовує масив.) Дійсно, однак, для більшості цілей це досить швидко, і ви, мабуть, вже його маєте.
можливо, ми могли б статиСталAVan

75
+1 для відповіді, оскільки в Android немає DataTypeConverter
Вайден

7
@maybeWeCouldStealAVan: JDK 7 тепер відкритий. Ми повинні надіслати виправлення для підвищення продуктивності printHexBinary?
kevinarpe

3
@maybeWeCouldStealAVan, будь ласка, поясніть, як це працює. Я дотримуюся здебільшого, але дуже люблю розуміти, що відбувається під час використання коду. Дякую!
jjNford

24
javax.xml.bind.DataTypeConverterвидаляється з Java 11.
The Impaler

421

Apache Commons Codec бібліотека має Hex - клас для робити саме цей вид роботи.

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

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

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) , був зручним способом перетворення a byte[]в шістнадцяткову рядок. DatatypeConverterКлас також включає безліч інших корисних методів даних маніпуляцій.

У Java 8 та новіших версіях JAXB входила до стандартної бібліотеки Java. Він був застарілий з Java 9 і видаляється з Java 11 , як частина зусиль , щоб перемістити всі пакети Java EE в свої бібліотеки. Це довга історія . Зараз javax.xml.bindне існує, і якщо ви хочете використовувати JAXB, який містить DatatypeConverter, вам потрібно буде встановити API JAXB та 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 . Це спосіб перенести класи javax в 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
Якщо це повільно, то що? У моєму випадку використання це лише для заяви про налагодження, тому дякую за цей фрагмент коду.
vikingsteve

8
Повторне використання бібліотеки шляхом включення додаткових файлів JAR в кілька десятків кБ не було б точно ефективним, якщо вам потрібна лише ця функція (на деяких платформах, таких як Android, весь Jar потрапляє в кінцеву програму). І іноді коротший і чіткіший код краще, коли продуктивність не потрібна.
personne3000

2
@ personne3000, можливо, але в цьому випадку вам потрібна підтримка потоку, а не функція єдиного дзвінка. це легко зрозуміти і запам'ятати, а отже, підтримувати.
Maarten Bodewes

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
Що стосується HashCode.fromBytes(checksum).toString()
Гуави

43

Цей простий oneliner працює для мене
String result = new BigInteger(1, inputBytes).toString(16);
EDIT - за допомогою цього вилучите провідні нулі, але він працював для мого використання. Дякую @Voicu за те, що вказав на це


56
Цей однолінійки опускає провідні нульові байти.
Voicu

@Voicu ... І це додасть нульовий 50% часу.
Maarten Bodewes

27

Ось кілька загальних варіантів, упорядкованих від простого (однолінійний) до складного (величезна бібліотека). Якщо вас цікавить ефективність, дивіться мікро-орієнтири нижче.

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

Одне дуже просте рішення - використовувати BigIntegerшістнадцяткове представлення:

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

Зауважте, що оскільки ця обробка чисел не є довільними рядками байтів, вона опустить провідні нулі - це може бути, а може і не бути тим, що ви хочете (наприклад, 000AE3проти 0AE33-байтного вводу). Це також дуже повільно, приблизно в 100 разів повільніше порівняно з наступним варіантом.

Варіант 2: фрагмент коду - розширений

Тут повнофункціональним, копіювати і pasteable фрагмент коду підтримує верхній / нижній регістр і порядок байтів . Він оптимізований для мінімізації складності пам'яті та максимізації продуктивності, а також повинен бути сумісний з усіма сучасними версіями 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 / декодер:

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 із 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, ваш код не може отримати доступ до іншого коду поза його модулем без явного декларування. Тому будьте в курсі, якщо у вас виняток:

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, 24GB Ram. Повний тест дивіться тут .



21

Я б використав щось подібне для фіксованої довжини, як хеши:

md5sum = String.format("%032x", new BigInteger(1, md.digest()));

2
Дякую, це так дотепно і доречно.
Deepan Prabhu Babu

17

Тут я знайшов три різні способи: 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 мс. Мабуть, найкраще за відсутності будь-яких інших функцій String, таких як формат.
Йосип Похоть

if (raw == null) return nullне провалюється швидко. Навіщо ти коли-небудь використовувати nullключ?
Maarten Bodewes

Я припускаю, що це звичка вводити перевірку. У цьому випадку ми забороняємо будь-яке виключення Null reference та залишаємо його для абонента для обробки поганих даних.
Майкл Бісб'єрг

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 Це можливо навіть із статичним кінцевим (інакше постійним) полем?
nevelis

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
Це дуже схоже на відповідь everconfusedGuy.
Scratte

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

Це трохи гнучкіша адаптація прийнятої відповіді. Особисто я зберігаю як прийняту відповідь, так і це перевантаження разом з нею, придатною для використання в інших контекстах.


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

2

Зазвичай я використовую наступний метод для налагодження заяви, але я не знаю, це найкращий спосіб зробити це чи ні

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

Додавання утиліти для простого функціонування - це не гарний варіант. Замість цього збирайте власні класи корисних програм. нижче можлива швидша реалізація.

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 мав можливість префіксувати нулі в toString).

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.