Wie konvertiere ich ein Byte-Array in eine Hex-Zeichenfolge in Java?


649

Ich habe ein Byte-Array, das mit Hex-Zahlen gefüllt ist, und das einfache Drucken ist ziemlich sinnlos, da es viele nicht druckbare Elemente gibt. Was ich brauche, ist der genaue Hexcode in Form von:3a5f771c


12
Probieren Sie es einfach zuerst aus und zeigen Sie uns, was Sie haben. Sie haben nichts zu verlieren und alles zu gewinnen. Integer hat eine toHexString(...)Methode, die helfen kann, wenn Sie danach suchen. Auch String.format(...)können einige nette Formatierung Tricks tun , um die Verwendung von %2xCode - String.
Luftkissenfahrzeug voller Aale


"Was ich brauche, ist der genaue Hexcode in Form von: 3a5f771c ..." - Sie haben nach einem genauen Formular gefragt, aber kein genaues Beispiel angegeben. Konvertieren Sie die ersten vier Bytes in eine Zeichenfolge und verketten Sie dann die Ellipsen mit der Zeichenfolge.
Jww

1
Mit Hilfe von Stream in Java 8 kann es einfach implementiert werden als: static String byteArrayToHex (byte [] a) {return IntStream.range (0, a.length) .mapToObj (i -> String.format ("% 02x") ", a [i])) .reduce ((acc, v) -> acc +" "+ v) .get (); }
Tibetty

Antworten:


900

Aus der Diskussion hier und insbesondere aus dieser Antwort geht hervor, dass dies die Funktion ist, die ich derzeit verwende:

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

Meine eigenen kleinen Benchmarks (eine Million Bytes tausendmal, 256 Bytes zehn Millionen Mal) zeigten, dass es viel schneller ist als jede andere Alternative, ungefähr die Hälfte der Zeit auf langen Arrays. Im Vergleich zu der Antwort, aus der ich sie übernommen habe, konnte durch das Umschalten auf bitweise Operationen - wie in der Diskussion vorgeschlagen - die Zeit für lange Arrays um etwa 20% verkürzt werden. (Bearbeiten: Wenn ich sage, dass es schneller als die Alternativen ist, meine ich den in den Diskussionen angebotenen alternativen Code. Die Leistung entspricht dem Commons Codec, der sehr ähnlichen Code verwendet.)

2k20-Version in Bezug auf Java 9-Kompaktzeichenfolgen:

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
Ich habe gerade javax.xml.bind.DataTypeConverter gefunden , einen Teil der Standarddistribution. Warum taucht das nicht auf, wenn Sie diese Art von Problem googeln? Viele hilfreiche Tools, einschließlich String printHexBinary(byte[])und byte[] parseHexBinary(String). printHexBinaryist jedoch viel (2x) langsamer als die Funktion in dieser Antwort. (Ich habe die Quelle überprüft; sie verwendet ein stringBuilder. parseHexBinaryVerwendet ein Array.) Wirklich, für die meisten Zwecke ist es jedoch schnell genug und Sie haben es wahrscheinlich bereits.
VielleichtWeCouldStealAVan

75
+1 für die Antwort, da Android keinen DataTypeConverter hat
Vaiden

7
@maybeWeCouldStealAVan: JDK 7 ist jetzt Open Source. Wir sollten einen Patch einreichen, um die Leistung für zu verbessern printHexBinary.
Kevinarpe

3
@maybeWeCouldStealAVan Könnten Sie bitte erklären, wie dies funktioniert. Ich folge größtenteils, mag es aber wirklich zu verstehen, was bei der Verwendung von Code passiert. Vielen Dank!
JJNford

24
javax.xml.bind.DataTypeConverterwird aus Java 11 entfernt.
The Impaler

420

Die Apache Commons Codec- Bibliothek verfügt über eine Hex- Klasse, die genau diese Art von Arbeit erledigt.

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 - Meine Ablehnung erfolgte vor 4 Monaten, daher bin ich mir nicht ganz sicher, was ich dachte, aber ich habe wahrscheinlich Einwände gegen die Größe der Bibliothek erhoben. Dies ist eine kleine Funktion innerhalb des Programms. Es ist nicht erforderlich, dem Projekt eine so umfangreiche Bibliothek hinzuzufügen, um es auszuführen.
ArtOfWarfare

6
@ArtOfWarefare Ich stimme zu, also anstatt import org.apache.commons.codec.*;Sie könntenimport org.apache.commons.codec.binary.Hex;
Cytinus

12
@ArtOfWarfare Ich muss nicht zustimmen. Das einzig Schreckliche ist, dass die Apache-Commons-Bibliotheken standardmäßig nicht in JRE und JDK enthalten sind. Es gibt einige Bibliotheken, die so nützlich sind, dass sie sich standardmäßig auf Ihrem Klassenpfad befinden sollten, und dies ist eine davon.
CorsiKa

28
Ich empfehle dringend, diese Antwort als Top-Antwort auszutauschen. Stimmen Sie immer ab, um eine gut getestete, performante Open-Source-Bibliothek über benutzerdefiniertem Code zu verwenden, der sich nicht verbessert.
Dmitriy Likhten

6
Oder wenn Sie BouncyCastle ( org.bouncycastle: bcprov-jdk15on ) verwenden, können Sie diese Klasse verwenden: org.bouncycastle.util.encoders.Hexmit dieser Methode:String toHexString(byte[] data)
Guillaume Husta

320

Die Methode javax.xml.bind.DatatypeConverter.printHexBinary(), die Teil der Java-Architektur für XML-Bindung (JAXB) ist , war eine bequeme Möglichkeit, eine byte[]in eine Hex-Zeichenfolge zu konvertieren . Die DatatypeConverterKlasse enthielt auch viele andere nützliche Datenmanipulationsmethoden.

In Java 8 und früheren Versionen war JAXB Teil der Java-Standardbibliothek. Es wurde als veraltet mit Java 9 und entfernt mit Java 11 , als Teil der Bemühungen , alle Java EE - Pakete in ihre eigenen Bibliotheken zu bewegen. Es ist eine lange Geschichte . Jetzt javax.xml.bindnicht vorhanden, und wenn Sie JAXB verwenden möchten, das enthält DatatypeConverter, müssen Sie die JAXB-API und JAXB Runtime von Maven installieren .

Anwendungsbeispiel:

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

Wird darin enden, dass:

000086003D

Diese Antwort ist dieselbe wie diese .


13
Eine gute Lösung, die leider nicht für Android gültig ist.
Kazriko

@Kazriko Vielleicht möchten Sie code.google.com/p/dalvik/wiki/JavaxPackages lesen . Es ist eine Möglichkeit, Javax-Klassen in Android zu integrieren. Aber wenn Sie nur in Hex konvertieren möchten, ist es die Mühe nicht wert.
PhoneixS

13
DatatypeConverter ist ab JDK 9
pmcollins

3
@PhoneixS Es ist immer noch vorhanden, aber nicht Teil der Standardlaufzeit (aufgrund von Java 9-Modulen).
Spotlight

2
Verlassen Sie sich nicht auf javax.xml.bind, es wird gut kompiliert, kann aber zur Laufzeit nicht gefunden werden. Wenn Sie dies tun, seien Sie bereit, mit java.lang.NoClassDefFoundError
Dmitry

227

Einfachste Lösung, keine externen Bibliotheken, keine Ziffernkonstanten:

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
Dies ist sehr langsam, im Durchschnitt 1000-mal langsamer (für 162 Bytes lang) als in der oberen Antwort. Vermeiden Sie die Verwendung von String.Format, wenn die Leistung wichtig ist.
Pt123

8
Vielleicht langsam. Es ist gut für Dinge, die gelegentlich passieren, wie zum Beispiel Login oder ähnliches.
Zeiger Null

29
Wenn es langsam ist, was dann? In meinem Anwendungsfall handelt es sich nur um eine Debug-Anweisung. Vielen Dank für dieses Codefragment.
Wikingersteve

8
Die Wiederverwendung einer Bibliothek durch Hinzufügen zusätzlicher JAR-Dateien mit mehreren Dutzend kB wäre nicht gerade effizient, wenn Sie nur diese Funktion benötigen (auf einigen Plattformen wie Android wird das gesamte Jar in die Endanwendung aufgenommen). Und manchmal ist kürzerer und klarerer Code besser, wenn keine Leistung benötigt wird.
personne3000

2
@ personne3000 vielleicht, aber in diesem Fall benötigen Sie Stream-Unterstützung, keine einzige Anruffunktion. Dieser ist leicht zu verstehen und zu merken und daher zu pflegen.
Maarten Bodewes

59

Eine Guavenlösung der Vollständigkeit halber:

import com.google.common.io.BaseEncoding;
...
byte[] bytes = "Hello world".getBytes(StandardCharsets.UTF_8);
final String hex = BaseEncoding.base16().lowerCase().encode(bytes);

Jetzt hexist "48656c6c6f20776f726c64".


In Guave können Sie auch verwenden new HashCode(bytes).toString().
mfulton26

1
Ab Guava 22.0 ist esHashCode.fromBytes(checksum).toString()
Devstr

41

Dieser einfache Oneliner funktioniert für mich BEARBEITEN
String result = new BigInteger(1, inputBytes).toString(16);
- Wenn Sie diesen verwenden, werden die führenden Nullen entfernt, aber sie haben für meinen Anwendungsfall funktioniert. Vielen Dank an @Voicu für den Hinweis


55
Dieser Oneliner löscht führende Null-Bytes.
Voicu

@Voicu ... Und es wird in 50% der Fälle eine führende Null hinzufügen.
Maarten Bodewes

26

Hier sind einige gängige Optionen, die von einfach (einzeilig) bis komplex (riesige Bibliothek) geordnet sind. Wenn Sie an Leistung interessiert sind, lesen Sie die folgenden Mikro-Benchmarks.

Option 1: Code-Snippet - Einfach

Eine sehr einfache Lösung ist die Verwendung der BigIntegerHex-Darstellung:

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

Da dies Zahlen behandelt, die keine willkürlichen Byte-Strings sind , werden führende Nullen weggelassen - dies kann das sein, was Sie wollen oder nicht (z. B. 000AE3vs 0AE3für eine 3-Byte-Eingabe). Dies ist auch sehr langsam, etwa 100x langsamer als bei der nächsten Option.

Option 2: Code-Snippet - Erweitert

Hier ist ein voll ausgestattetes, kopierfähiges und einfügbares Code-Snippet, das Groß- / Kleinbuchstaben und Endianness unterstützt . Es ist optimiert, um die Speicherkomplexität zu minimieren und die Leistung zu maximieren, und sollte mit allen modernen Java-Versionen (5+) kompatibel sein.

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

Den vollständigen Quellcode mit Apache v2 Lizenz und Decoder finden Sie hier .

Option 3: Verwenden einer kleinen optimierten Bibliothek: bytes-java

Während ich an meinem vorherigen Projekt gearbeitet habe, habe ich dieses kleine Toolkit für die Arbeit mit Bytes in Java erstellt. Es hat keine externen Abhängigkeiten und ist mit Java 7+ kompatibel. Es enthält unter anderem einen sehr schnellen und gut getesteten HEX en / decoder:

import at.favre.lib.bytes.Bytes;
...
Bytes.wrap(someByteArray).encodeHex()

Sie können es auf Github auschecken: bytes-java .

Option 4: Apache Commons Codec

Natürlich gibt es die guten alten Codecs . ( warnende Meinung voraus ) Während ich an dem oben beschriebenen Projekt arbeitete, analysierte ich den Code und war ziemlich enttäuscht. Viele doppelte unorganisierte Codes, veraltete und exotische Codecs sind wahrscheinlich nur für sehr wenige und ziemlich überentwickelte und langsame Implementierungen beliebter Codecs (insbesondere Base64) nützlich. Ich würde daher eine fundierte Entscheidung treffen, wenn Sie es oder eine Alternative verwenden möchten. Wenn Sie es dennoch verwenden möchten, finden Sie hier einen Code-Ausschnitt:

import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(someByteArray));

Option 5: Google Guava

Meistens haben Sie bereits Guave als Abhängigkeit. Wenn ja, verwenden Sie einfach:

import com.google.common.io.BaseEncoding;
...
BaseEncoding.base16().lowerCase().encode(someByteArray);

Option 6: Federsicherheit

Wenn Sie das Spring-Framework mit Spring Security verwenden , können Sie Folgendes verwenden:

import org.springframework.security.crypto.codec.Hex
...
new String(Hex.encode(someByteArray));

Option 7: Hüpfburg

Wenn Sie bereits das Sicherheits-Framework Bouncy Castle verwenden , können Sie dessen Hexutil verwenden:

import org.bouncycastle.util.encoders.Hex;
...
Hex.toHexString(someByteArray);

Nicht wirklich Option 8: Java 9+ -Kompatibilität oder 'JAXBs nicht verwenden javax / xml / bind / DatatypeConverter'

In früheren Java-Versionen (8 und niedriger) war der Java-Code für JAXB als Laufzeitabhängigkeit enthalten. Seit Java 9 und Jigsaw Modularisierung Ihr Code ohne explizite Deklaration nicht auf anderen Code außerhalb seines Moduls zugreifen. Seien Sie sich also bewusst, wenn Sie eine Ausnahme erhalten wie:

java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

beim Ausführen auf einer JVM mit Java 9+. Wenn ja, wechseln Sie die Implementierung zu einer der oben genannten Alternativen. Siehe auch dies Frage .


Mikro-Benchmarks

Hier sind die Ergebnisse eines einfachen JMH- Mikro-Benchmarks, der Byte-Arrays unterschiedlicher Größe codiert . Die Werte sind Operationen pro Sekunde, also ist höher besser. Beachten Sie, dass Mikro-Benchmarks sehr oft kein reales Verhalten darstellen. Nehmen Sie diese Ergebnisse daher mit einem Körnchen Salz.

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

Technische Daten: JDK 8u202, i7-7700K, Win10, 24 GB RAM. Den vollständigen Benchmark finden Sie hier .



21

Ich würde so etwas für feste Länge verwenden, wie Hashes:

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

2
Danke, das ist so markig und angemessen.
Deepan Prabhu Babu

17

Ich habe hier drei verschiedene Möglichkeiten gefunden: http://www.rgagnon.com/javadetails/java-0596.html

Das eleganteste, wie er auch bemerkt, denke ich, ist dieses:

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

Andere Methoden liefen auf meinem 64-Byte-Beispiel in 5 ms, dieses läuft in 0 ms. Wahrscheinlich am besten, da keine anderen String-Funktionen wie das Format vorhanden sind.
Joseph Lust

if (raw == null) return nullist nicht schnell ausfallen. Warum würden Sie jemals einen nullSchlüssel verwenden?
Maarten Bodewes

Ich nehme an, es ist eine Gewohnheit, Validierung einzugeben. In diesem Fall verhindern wir jede Nullreferenzausnahme und überlassen es dem Aufrufer, fehlerhafte Daten zu verarbeiten.
Michael Bisbjerg

16

Bei den geringen Kosten für das Speichern der Nachschlagetabelle ist diese Implementierung einfach und sehr schnell.

 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
Warum nicht das BYTE2HEXArray mit einem einfachen forZyklus initialisieren ?
icza

@icza Ist das überhaupt mit einem statischen Endfeld (auch bekannt als Konstante) möglich?
Nevelis

1
@nevelis Es kann in einem static { }Block zugewiesen werden .
よ ル ち ゃ ん だ よ

1
@icza, weil es schneller ist, eine Nachschlagetabelle fest zu codieren, als sie zu generieren. Hier wird die Speicherkomplexität mit der Zeitkomplexität gehandelt, d. H. braucht mehr Speicher, aber schneller (jeweils ein wenig an beiden Enden)
Patrick Favre

8

Wie wäre es damit?

    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

Wir müssen keine externe Bibliothek verwenden oder Code basierend auf Schleifen und Konstanten schreiben.
Ist genug nur das:

byte[] theValue = .....
String hexaString = new BigInteger(1, theValue).toString(16);

Dies ist der Antwort von everconfusedGuy sehr ähnlich.
Scratte

2

Ich benutze das lieber:

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

Es ist eine etwas flexiblere Anpassung der akzeptierten Antwort. Persönlich behalte ich sowohl die akzeptierte Antwort als auch diese Überlastung bei, die in mehr Kontexten verwendet werden kann.


Die ursprüngliche Frage war für Byte [] zu String. Suchen Sie hexadezimal nach Bytes [] oder stellen Sie eine andere Frage: @NonExistent.
Bamaco

2

Normalerweise verwende ich die folgende Methode für die Debuf-Anweisung, aber ich weiß nicht, ob dies der beste Weg ist oder nicht

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
Wenn Ihr Debuffer einen schlechten Tag hat, versuchen Sie, die StringBuilder-Instanziierung mit einer Reihe von Zeichen zu unterstützen, um Folgendes zu unterstützen : StringBuilder buf = new StringBuilder(data.length * 2);.
Graubart

2

Ok, es gibt eine Reihe von Möglichkeiten, dies zu tun. Wenn Sie sich jedoch für die Verwendung einer Bibliothek entscheiden, würde ich empfehlen, in Ihrem Projekt nachzuschauen, ob in einer Bibliothek, die bereits Teil Ihres Projekts ist, etwas implementiert wurde, bevor Sie eine neue Bibliothek hinzufügen nur um das zu tun. Zum Beispiel, wenn Sie noch nicht haben

org.apache.commons.codec.binary.Hex

Vielleicht hast du ...

org.apache.xerces.impl.dv.util.HexBin


2

Wenn Sie das Spring Security-Framework verwenden, können Sie Folgendes verwenden:

import org.springframework.security.crypto.codec.Hex

final String testString = "Test String";
final byte[] byteArray = testString.getBytes();
System.out.println(Hex.encode(byteArray));

2

Das Hinzufügen eines Utility-JAR für einfache Funktionen ist keine gute Option. Stellen Sie stattdessen Ihre eigenen Dienstprogrammklassen zusammen. Folgendes ist eine schnellere Implementierung möglich.

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

Eine kleine Variante der von @maybewecouldstealavan vorgeschlagenen Lösung, mit der Sie N Bytes in der Ausgabe-Hex-Zeichenfolge visuell bündeln können:

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

Das ist:

bytesToHexString("..DOOM..".toCharArray().getBytes(), 2);
2E2E 444F 4F4D 2E2E

bytesToHexString("..DOOM..".toCharArray().getBytes(), 4);
2E2E444F 4F4D2E2E

1

Auf dieser Seite kann keine Lösung gefunden werden, die dies nicht tut

  1. Verwenden Sie eine Schleife
  2. Verwenden Sie javax.xml.bind.DatatypeConverter, das gut kompiliert, aber zur Laufzeit häufig java.lang.NoClassDefFoundError auslöst.

Hier ist eine Lösung, die die oben genannten Mängel nicht aufweist (keine Versprechen, meine hat jedoch keine anderen Mängel)

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

Ich konnte dies nicht unter 62 Opcodes bekommen, aber wenn Sie ohne 0-Auffüllung leben können, falls das erste Byte kleiner als 0x10 ist, dann verwendet die folgende Lösung nur 23 Opcodes. Zeigt wirklich, wie "einfach, sich selbst zu implementieren" -Lösungen wie "Pad mit einer Null, wenn die Zeichenfolgenlänge ungerade ist" ziemlich teuer werden können, wenn eine native Implementierung noch nicht verfügbar ist (oder in diesem Fall, wenn BigInteger die Option hatte, Nullen vorangestellt zu haben 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

Meine Lösung basiert auf der Lösung von MaybeWeCouldStealAVan, basiert jedoch nicht auf zusätzlich zugewiesenen Nachschlagetabellen. Es werden keine "int-to-char" -Cast-Hacks verwendet (tatsächlich wird Character.forDigit()ein Vergleich durchgeführt, um zu überprüfen, was die Ziffer wirklich ist) und daher möglicherweise etwas langsamer. Bitte benutzen Sie es, wo immer Sie wollen. Prost.

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

// Das Verschieben von Bytes ist effizienter // Sie können dieses auch verwenden

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

Wenn Sie nach einem genau solchen Byte-Array für Python suchen, habe ich diese Java-Implementierung in Python konvertiert.

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

Hier ist eine java.util.Base64ähnliche Implementierung (teilweise), ist es nicht hübsch?

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);
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.