it-swarm.com.ru

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

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

543
Andre

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

private final static char[] hexArray = "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] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
}

Мои собственные крошечные тесты (миллион байтов в тысячу раз, 256 байтов в 10 миллионов раз) показали, что он намного быстрее, чем любая другая альтернатива, примерно вдвое меньше для длинных массивов. По сравнению с ответом, который я получил, переключение на побитовые операции - как предложено в обсуждении - сократило время на длинные массивы примерно на 20%. (Изменить: когда я говорю, что это быстрее, чем альтернативы, я имею в виду альтернативный код, предлагаемый в обсуждениях. Производительность эквивалентна кодеку Commons, который использует очень похожий код.)

791
maybeWeCouldStealAVan

Библиотека 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 ) );
356
chooban

Используйте DatatypeConverter.printHexBinary(). Вы можете прочитать его документацию в http://docs.Oracle.com/javase/6/docs/api/javax/xml/bind/DatatypeConverter.html

Например:

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

Приведет к:

000086003D

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

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

307
PhoneixS

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

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

Решение 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".

44
Stephan202

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

41
everconfusedGuy

Используйте DataTypeConverter classjavax.xml.bind.DataTypeConverter

String hexString = DatatypeConverter.printHexBinary(bytes[] raw);

22
Coral

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

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

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

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

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

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

    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;
    }
8
Manan Bakshi

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

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

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

2
Bamaco

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

org.Apache.commons.codec.binary.Hex

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

org.Apache.xerces.impl.dv.util.HexBin

2
Aaron Cooley

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

private static String digits = "0123456789abcdef";

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

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

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

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

import Java.math.BigInteger;

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

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

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

        return result;
    }

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

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

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

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

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

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

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

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

Небольшой вариант решения, предложенного @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
Campa

Если вы используете платформу 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));
0
java-addict301

Мое решение основано на решении может быть 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
Netherwire
          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);
        }
0
Rajneesh Shukla

Вот реализация 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
fuweichin
  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
田咖啡

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

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
BluePurse

Если вы ищете такой же байтовый массив для 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
SkippsDev
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
kakopappa