Java-Code Zum Konvertieren von Byte in Hexadezimal

184

Ich habe ein Array von Bytes. Ich möchte, dass jeder Byte-String dieses Arrays in seine entsprechenden Hexadezimalwerte konvertiert wird.

Gibt es in Java eine Funktion zum Konvertieren eines Byte-Arrays in Hexadezimal?

Vivek
quelle
2
Was Sie in Java als Byte-Array bezeichnen, wird in anderen Sprachen als Byte-String bezeichnet (z. B. docs.racket-lang.org/guide/bytestrings.html )
Patrick Favre,

Antworten:

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

Siehe auch

  • java.util.Formatter Syntax
    • %[flags][width]conversion
      • Flag '0'- Das Ergebnis wird mit Nullen aufgefüllt
      • Breite 2
      • Konvertierung 'X'- Das Ergebnis wird als hexadezimale Ganzzahl in Großbuchstaben formatiert

Wenn Sie sich den Text der Frage ansehen, ist es auch möglich, dass Folgendes angefordert wird:

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

Mehrere Antworten hier verwendet Integer.toHexString(int); Dies ist machbar, aber mit einigen Einschränkungen. Da der Parameter ein ist int, wird eine erweiterte primitive Konvertierung für das byteArgument durchgeführt, die eine Vorzeichenerweiterung beinhaltet.

    byte b = -1;
    System.out.println(Integer.toHexString(b));
    // prints "ffffffff"

Das 8-Bit byte, das in Java signiert ist, wird auf 32 Bit erweitert int. Um diese Vorzeichenerweiterung effektiv rückgängig zu machen, kann man das bytemit maskieren 0xFF.

    byte b = -1;
    System.out.println(Integer.toHexString(b & 0xFF));
    // prints "ff"

Ein weiteres Problem bei der Verwendung toHexStringist, dass keine Nullen aufgefüllt werden:

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

Beide Faktoren zusammen sollten die String.formatLösung bevorzugter machen.

Verweise

Polygenschmierstoffe
quelle
@Vivek: Was ist "ein enorm großer Wert"? Was ist die Eingabe und was ist die Ausgabe?
Polygenschmierstoffe
Lassen Sie mich noch einmal erklären. Ich habe eine Sammlung von Byte-Strings in einem Array. Aber was ich tun muss, ist jedes Byte separat zu analysieren. Ich möchte also nicht an dem gesamten Array arbeiten, sondern an einer einzelnen Byte-Zeichenfolge gleichzeitig, das ist eine Komponente dieses Arrays. Die Verwirrung entstand aufgrund des Wortes " Array ". Jetzt im folgenden Code "Byte bv = 10; String hexString = Integer.toHexString (bv);" CAse 1 (Byte empfangen: 68 Hex-Ausgabe :: 44) Fall: 2 (Byte empfangen: -46 Hex-Ausgabe :: ffffffd2) ......... Warum erhalte ich für einige Werte ein so unerwartetes Ergebnis?
Vivek
1
@ Vivek: Lies meine Antwort über die Verwendung toHexString. Sie müssen es mit maskieren & 0xFF, dh Integer.toHexString(-46 & 0xFF)ist "d2".
Polygenschmierstoffe
@polygenelubricants: Vielen Dank. Es scheint, endlich funktioniert der Code einwandfrei. Ist es sicher, jetzt die Funktion HexString zu verwenden? Oder könnte der Ansatz einige Lücken aufweisen?
Vivek
1
@Vivek: Es ist "sicher", Sie müssen nur vorsichtig sein und sicherstellen, dass Sie den byteWert & 0xFFjedes Mal maskieren . Die formatobige Lösung erfordert möglicherweise auch eine Maskierung, je nachdem, was Sie tatsächlich als Argument verwenden.
Polygenschmierstoffe
65

Ich poste, weil keine der vorhandenen Antworten erklärt, warum ihre Ansätze funktionieren, was meiner Meinung nach für dieses Problem wirklich wichtig ist. In einigen Fällen erscheint die vorgeschlagene Lösung dadurch unnötig kompliziert und subtil. Zur Veranschaulichung werde ich einen ziemlich einfachen Ansatz angeben, aber ich werde ein wenig mehr Details zur Veranschaulichung bereitstellen warum es funktioniert.

Was versuchen wir zuerst zu tun? Wir möchten einen Bytewert (oder ein Array von Bytes) in eine Zeichenfolge konvertieren, die einen hexadezimalen Wert in ASCII darstellt. Schritt eins ist also, genau herauszufinden, was ein Byte in Java ist:

Der Byte-Datentyp ist eine 8-Bit-Zweierkomplement-Ganzzahl mit Vorzeichen . Es hat einen Mindestwert von -128 und einen Höchstwert von 127 (einschließlich). Der Byte-Datentyp kann nützlich sein, um Speicher in großen Arrays zu speichern, in denen die Speichereinsparung tatsächlich von Bedeutung ist. Sie können auch anstelle von int verwendet werden, wenn ihre Grenzen zur Verdeutlichung Ihres Codes beitragen. Die Tatsache, dass der Bereich einer Variablen begrenzt ist, kann als Dokumentationsform dienen.

Was bedeutet das? Ein paar Dinge: Erstens und vor allem bedeutet dies, dass wir mit 8-Bit arbeiten . So können wir beispielsweise die Zahl 2 als 0000 0010 schreiben. Da es sich jedoch um ein Zweierkomplement handelt, schreiben wir eine negative 2 wie folgt: 1111 1110. Dies bedeutet auch, dass die Konvertierung in hex sehr einfach ist. Das heißt, Sie konvertieren einfach jedes 4-Bit-Segment direkt in hexadezimal. Beachten Sie, dass Sie zuerst das Zweierkomplement verstehen müssen, um negative Zahlen in diesem Schema zu verstehen. Wenn Sie das Zweierkomplement noch nicht verstehen, können Sie hier eine hervorragende Erklärung lesen: http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html


Zweierkomplement in Hex im Allgemeinen umwandeln

Sobald eine Zahl im Zweierkomplement steht, ist es kinderleicht, sie in Hex umzuwandeln. Im Allgemeinen ist die Konvertierung von binär nach hex sehr einfach, und wie Sie in den nächsten beiden Beispielen sehen werden, können Sie direkt vom Zweierkomplement zum Hex wechseln.

Beispiele

Beispiel 1: Konvertieren Sie 2 in Hex.

1) Konvertieren Sie zuerst 2 in Binär in Zweierkomplement:

2 (base 10) = 0000 0010 (base 2)

2) Konvertieren Sie nun Binär in Hex:

0000 = 0x0 in hex
0010 = 0x2 in hex

therefore 2 = 0000 0010 = 0x02. 

Beispiel 2: Konvertiere -2 (im Zweierkomplement) in Hex.

1) Konvertieren Sie zuerst -2 in binär im Zweierkomplement:

-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) Jetzt in Hex konvertieren:

1111 = 0xF in hex
1110 = 0xE in hex

therefore: -2 = 1111 1110 = 0xFE.


Dies in Java tun

Nachdem wir uns nun mit dem Konzept befasst haben, werden Sie feststellen, dass wir durch einfaches Maskieren und Verschieben das erreichen können, was wir wollen. Der Schlüssel zum Verständnis ist, dass das Byte , das Sie konvertieren möchten, bereits zu zweit vorliegt. Sie machen diese Konvertierung nicht selbst. Ich denke, dies ist ein wichtiger Punkt der Verwirrung in dieser Frage. Nehmen Sie zum Beispiel das folgende Byte-Array:

byte[] bytes = new byte[]{-2,2};

Wir haben sie oben nur manuell in hexadezimal konvertiert, aber wie können wir das in Java machen? Hier ist wie:

Schritt 1: Erstellen Sie einen StringBuffer für unsere Berechnung.

StringBuffer buffer = new StringBuffer();

Schritt 2: Isolieren Sie die Bits höherer Ordnung, konvertieren Sie sie in hexadezimal und hängen Sie sie an den Puffer an

Wenn die Binärzahl 1111 1110 gegeben ist, können wir die Bits höherer Ordnung isolieren, indem wir sie zuerst um 4 verschieben und dann den Rest der Zahl auf Null setzen. Logischerweise ist dies einfach, jedoch führen die Implementierungsdetails in Java (und vielen Sprachen) aufgrund der Zeichenerweiterung zu einer Falte. Wenn Sie einen Bytewert verschieben, konvertiert Java Ihren Wert zunächst in eine Ganzzahl und führt dann eine Vorzeichenerweiterung durch. Während Sie also erwarten würden, dass 1111 1110 >> 4 0000 1111 ist, wird es in Java in Wirklichkeit als das Zweierkomplement 0xFFFFFFFF dargestellt!

Kehren wir also zu unserem Beispiel zurück:

1111 1110 >> 4 (shift right 4) = 1111 1111 1111 1111 1111 1111 1111 1111 (32 bit sign-extended number in two's complement)

Wir können dann die Bits mit einer Maske isolieren:

1111 1111 1111 1111 1111 1111 1111 1111 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1111
therefore: 1111 = 0xF in hex. 

In Java können wir dies alles auf einmal tun:

Character.forDigit((bytes[0] >> 4) & 0xF, 16);

Die forDigit-Funktion ordnet nur die Zahl, die Sie übergeben, der Menge der Hexadezimalzahlen 0-F zu.

Schritt 3: Als nächstes müssen wir die Bits niedrigerer Ordnung isolieren. Da sich die gewünschten Bits bereits an der richtigen Position befinden, können wir sie einfach ausblenden:

1111 1110 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1110 (recall sign extension from before)
therefore: 1110 = 0xE in hex.  

Wie zuvor können wir dies in Java auf einen Schlag tun:

Character.forDigit((bytes[0] & 0xF), 16);

Wenn wir dies alles zusammenfügen, können wir es als for-Schleife ausführen und das gesamte Array konvertieren:

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

Hoffentlich macht diese Erklärung die Dinge für diejenigen unter Ihnen klarer, die sich genau fragen, was in den vielen Beispielen im Internet vor sich geht. Hoffentlich habe ich keine ungeheuren Fehler gemacht, aber Vorschläge und Korrekturen sind sehr willkommen!

jsinglet
quelle
4
beste Antwort! Die symetrische Implementierung eines hexadezimalen Strings in ein Byte würde dann konvertieren Character.digit(), wie(byte) ((Character.digit(str.charAt(0), 16) << 4) + Character.digit(str.charAt(1), 16))
ericbn
21

Der schnellste Weg, den ich bisher gefunden habe, ist der folgende:

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

Es ist ~ 50x schneller als String.format. wenn du es testen willst:

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
        }

    }
}

Bearbeiten : Ich habe gerade etwas gefunden, das nur ein bisschen schneller ist und in einer Zeile bleibt, aber nicht mit JRE 9 kompatibel ist . Die Verwendung erfolgt auf eigenes Risiko

import javax.xml.bind.DatatypeConverter;

DatatypeConverter.printHexBinary(raw);
Crystark
quelle
2
DatatypeConverter ist in Java 9 nicht mehr verfügbar. Das Gefährliche ist, dass Code, der ihn verwendet, unter Java 1.8 oder früher kompiliert wird (Java 9 mit früheren Quelleneinstellungen), unter Java 9 jedoch eine Laufzeitausnahme erhält.
Stephen M -on strike-
Ich zweiter @ StephenMs Punkt: Wenn Sie dies mit jre9 verwenden, stürzt es mit ClassNotFound Exception ab
Patrick Favre
Tatsächlich kann die Quellcodemethode einfach printHexBinary aus src.zip von jdk extrahiert werden, was 1 Mal schneller zu sein scheint als die erste Methode.
Obst
1
Wenn Sie mit dem char-Array für die HEXES-Konstante anstelle von String und charAt () arbeiten, erhalten Sie ~ 20% mehr Geschwindigkeit.
Dyorgio
15

Versuchen Sie Folgendes:

byte bv = 10;
String hexString = Integer.toHexString(bv);

Umgang mit Array (wenn ich Sie richtig verstanden habe):

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

Wie bereits erwähnt, String.format()ist Polygenelubricants die richtige Antwort im Vergleich zu Integer.toHexString()(da es richtig mit negativen Zahlen umgeht).

0x2D9A3
quelle
2
Dies wird verlängern, zB versuchen -1.
Polygenschmierstoffe
Byte bv = 10; String hexString = Integer.toHexString (bv); Dies scheint zu funktionieren. Ich kann es einzeln auf jedes Element des Arrays anwenden. Der andere Code (Umgang mit dem Array) gibt einen zu großen Wert zurück. Was könnte der Grund dafür sein?
Vivek
@Vivek, das liegt daran, dass in diesem Fall bvein einzelnes Hexadezimalzeichen zurückgegeben wird . Während der Rest des Codes eine Zeichenfolge mit hexadezimalen Zeichen zurückgibt . Ich habe den Code mit dem Delimeter geändert, damit Sie ihn jetzt verstehen können.
0x2D9A3
@Bar: Sie können weiterhin verwenden, Integer.toHexStringwenn Sie die bytemit 0xFFzum Rückgängigmachen der Zeichenerweiterung maskieren .
Polygenelubricants
CAse 1 (Byte empfangen: 68 Hex-Ausgabe :: 44) Fall: 2 (Byte empfangen: -46 Hex-Ausgabe :: ffffffd2) Ich erhalte unerwartete Ausgabewerte bei negativen Byte-Arrays ... Wie gehe ich damit um?
Vivek
13

Die beste Lösung ist dieser Badass Einzeiler:

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

wie hier erwähnt

Luchs
quelle
4
DatatypeConverter ist in Java 9 nicht mehr verfügbar. Das Gefährliche ist, dass Code, der ihn verwendet, unter Java 1.8 oder früher kompiliert wird (Java 9 mit früheren Quelleneinstellungen), unter Java 9 jedoch eine Laufzeitausnahme erhält.
Stephen M -on strike-
Traurig, wenn du sagst, dass es nicht in jdk9 ist. new BigInteger(byteArray).toString(16)ist dann der richtige Weg. Gibt es Perf Probleme damit?
Prayagupd
Vielleicht keine Perf-Probleme, aber es werden führende Nullen fehlen (da sie für eine Zahl wie BigInteger bedeutungslos sind)
Friso
Sieht so aus, als ob es immer noch in den Java 9-Dokumenten enthalten ist. Es scheint also
Brad Parks
Ich denke , wie erklärt sich hier noch in Ordnung ist für java9 zu verwenden, aber werden entfernt in Zukunft Java - Versionen. Sie können es ab Version 2.3.0 auch weiterhin mit dem 'neuen' eigenständigen Jaxb-Modul verwenden .
Luchs
11

Wenn Sie eine Hex-Darstellung mit konstanter Breite wünschen, dh 0Aanstelle von A, damit Sie die Bytes eindeutig wiederherstellen können, versuchen Sie format():

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

Eine kurze und einfache Möglichkeit, byte[]eine Hex-Zeichenfolge zu konvertieren , indem Sie Folgendes verwenden BigInteger:

import java.math.BigInteger;

byte[] bytes = new byte[] {(byte)255, 10, 20, 30};
String hex = new BigInteger(1, bytes).toString(16);
System.out.println(hex); // ff0a141e

Wie es funktioniert?

Die integrierte Systemklassenklassejava.math.BigInteger ( java.math.BigInteger ) ist mit Binär- und Hex-Daten kompatibel:

  • Es hat einen Konstruktor BigInteger(signum=1, byte[]), mit dem eine große Ganzzahl erstellt werden kann byte[](setzen Sie den ersten Parameter signum= 1, um die negativen Bytes korrekt zu behandeln).
  • Verwenden Sie BigInteger.toString(16)diese Option , um die große Ganzzahl in eine Hex- Zeichenfolge umzuwandeln
  • Um eine Hex-Zahl zu analysieren, verwenden Sie new BigInteger("ffa74b", 16)- behandelt die führende Null nicht richtig

Wenn Sie die führende Null im Hex-Ergebnis haben möchten , überprüfen Sie deren Größe und fügen Sie gegebenenfalls die fehlende Null hinzu:

if (hex.length() % 2 == 1)
    hex = "0" + hex;

Anmerkungen

Verwenden Sie new BigInteger(1, bytes)stattdessen new BigInteger(bytes), weil Java " vom Design her fehlerhaft " ist und der byteDatentyp keine Bytes, sondern vorzeichenbehaftete winzige Ganzzahlen enthält [-128 ... 127]. Wenn das erste Byte negativ ist, wird BigIntegerdavon ausgegangen, dass Sie eine negative große Ganzzahl übergeben. Übergeben Sie einfach 1als ersten Parameter ( signum=1).

Die Rückkonvertierung von hex zu inbyte[] ist schwierig: Manchmal tritt eine führende Null in die erzeugte Ausgabe ein und sollte wie folgt gereinigt werden:

byte[] bytes = new BigInteger("ffa74b", 16).toByteArray();
if (bytes[0] == 0) {
    byte[] newBytes = new byte[bytes.length - 1];
    System.arraycopy(bytes, 1, newBytes, 0, newBytes.length);
    bytes = newBytes;
}

Die letzte Note ist die, wenn die byte[]mehrere führende Nullen hat, gehen sie verloren.

Svetlin Nakov
quelle
1
Wenn das führende Byte einen Dezimalwert von weniger als 16 hat, erhalten Sie auch eine Zeichenfolge mit einer ungeraden Anzahl von Hex-Zeichen.
Alex Jorgenson
8

Wenn Sie gerne eine externe Bibliothek verwenden, verfügt die org.apache.commons.codec.binary.HexKlasse über eine encodeHexMethode, die a nimmt byte[]und a zurückgibt char[]. Diese Methode ist VIEL schneller als die Formatierungsoption und kapselt die Details der Konvertierung. Kommt auch mit einer decodeHexMethode für die entgegengesetzte Umwandlung.

Ajrskelton
quelle
4
Noch einfacher ist es, die integrierten Funktionen javax.xml.bind.DatatypeConverter / parseHexBinary und printHexBinary zu verwenden. Siehe stackoverflow.com/questions/9655181/…
Alan Thompson
2
+1 auf diese Option. Das Hex hat auch eine Methode encodeHexString, die ein Byte [] nimmt und einen String zurückgibt.
Mingjiang Shi
Vergessen Sie nicht, dass der javaxNamespace nicht immer verfügbar ist.
Mene
7

Sie können die Methode aus der Bouncy Castle Provider- Bibliothek verwenden:

org.bouncycastle.util.encoders.Hex.toHexString(byteArray);

Das Bouncy Castle Crypto-Paket ist eine Java-Implementierung kryptografischer Algorithmen. Diese JAR enthält JCE-Provider und eine Lightweight-API für die Bouncy Castle Cryptography-APIs für JDK 1.5 bis JDK 1.8.

Maven-Abhängigkeit:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.60</version>
</dependency>

oder aus dem Apache Commons Codec :

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

Das Apache Commons Codec-Paket enthält einfache Encoder und Decoder für verschiedene Formate wie Base64 und Hexadecimal. Zusätzlich zu diesen weit verbreiteten Codierern und Decodierern enthält das Codec-Paket auch eine Sammlung von Dienstprogrammen zur phonetischen Codierung.

Maven-Abhängigkeit:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.11</version>
</dependency>
Genauso wie
quelle
Ja, dies ist die beste Lösung , erfordert jedoch eine externe Bibliothek: Apache Commons Codec ( mvnrepository.com/artifact/commons-codec/commons-codec/1.11 ) oder BouncyCastle Provider ( mvnrepository.com/artifact/org.bouncycastle/bcprov- jdk15on / 1.60 )
Svetlin Nakov
5

Dies ist der Code, den ich bisher am schnellsten ausgeführt habe. Ich habe es auf 109015-Byte-Arrays mit einer Länge von 32 in 23 ms ausgeführt. Ich habe es auf einer VM ausgeführt, damit es auf Bare Metal wahrscheinlich schneller ausgeführt wird.

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<l; i++ ){
        out[j++] = HEX_DIGITS[(0xF0 & data[i]) >>> 4];
        out[j++] = HEX_DIGITS[0x0F & data[i]];
    }
    return out;
}

Dann kannst du es einfach tun

String s = new String( encodeHex(myByteArray) );
Jerinaw
quelle
3
BigInteger n = new BigInteger(byteArray);
String hexa = n.toString(16));
Wender
quelle
Funktioniert nicht: BigInteger(byteArrayOf(-1, 2, 3, 4, 5)).toString(16)kehrt zurück"-fdfcfbfb"
Martin Vysny
Es ist ein richtiges Ergebnis. Sie arbeiten mit den Bytes '-1', '2' ... '5'. Diese Bytes haben keine Visualisierung ( unicode.org ). Wenn Sie mit dem Literal '-1', '2' ... '5' arbeiten möchten, sollten Sie mit den Zeichenfolgenwerten arbeiten.
Wender
Es ist ein falsches Ergebnis. Der Java-Bytewert -1 ist tatsächlich 0xFF (es ist dasselbe wie (int) 255), da Java-Bytes signiert sind, daher sollte das Ergebnis sein FF02030405. Wenn Sie die oben beschriebene @ Jerinaw-Lösung ausprobieren, wird die richtige Ausgabe gedruckt. Siehe auch die Lösung von Svetlin Nakov unten.
Martin Vysny
2

Hier ist eine einfache Funktion zum Konvertieren von Byte in Hexadezimal

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

Andere haben den allgemeinen Fall behandelt. Wenn Sie jedoch ein Byte-Array einer bekannten Form haben, beispielsweise eine MAC-Adresse, können Sie:

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]); 
jww
quelle
1

Das Erstellen (und Zerstören) einer Reihe von StringInstanzen ist kein guter Weg, wenn die Leistung ein Problem darstellt.

Bitte ignorieren Sie diese ausführlichen (doppelten) Argumente, die Anweisungen überprüfen if. Das ist für (andere) Bildungszwecke.

Vollständiges Maven-Projekt: http://jinahya.googlecode.com/svn/trunk/com.googlecode.jinahya/hex-codec/

Codierung...

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

Dekodierung ...

/**
 * 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);
}
Jin Kwon
quelle
1

Dies ist ein sehr schneller Weg. Keine externen Bibliotheken erforderlich.

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);
    }
Bapho
quelle
1

Ich konnte nicht herausfinden, was genau Sie mit Byte-String gemeint haben, aber hier sind einige Konvertierungen von Byte zu String und umgekehrt. Natürlich gibt es in den offiziellen Dokumentationen noch viel mehr

Integer intValue = 149;

Der entsprechende Bytewert ist:

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

Holen Sie sich den Integer-Wert von einer Byte-Variablen zurück:

Integer anInt = byteValue.intValue(); // This will convert the byteValue variable to a signed Integer

Von Byte und Integer bis Hex String:
So mache ich das:

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

Konvertieren eines Bytes von Bytes in eine Hex-Zeichenfolge:
Soweit ich weiß, gibt es keine einfache Funktion, um alle Elemente in einem Array von einigen Objectin Elemente eines anderen zu konvertieren. ObjectSie müssen dies also selbst tun. Sie können folgende Funktionen verwenden:

Von Byte [] zu String:

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

Und von Hex-String zu Byte []:

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

Es ist zu spät, aber ich hoffe, das könnte einigen anderen helfen;)

Mehdi
quelle
1

Es gibt Ihre schnelle Methode:

    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];
    }
Schleife
quelle
1
hässlich, aber wahrscheinlich sehr effizient. :-)
Rich S
1

Genau wie einige andere Antworten, empfehlen ich zu verwenden String.format()und BigInteger. Um das Byte-Array jedoch als Big-Endian-Binärdarstellung anstelle einer Zweikomplement-Binärdarstellung (mit Vorzeichen und unvollständiger Verwendung des möglichen Hex-Wertebereichs) zu interpretieren, verwenden Sie BigInteger (int signum, Byte [] -Größe) und nicht BigInteger (Byte [] val) ) .

Verwenden Sie beispielsweise für ein Byte-Array der Länge 8:

String.format("%016X", new BigInteger(1,bytes))

Vorteile:

  • führende Nullen
  • kein signum
  • nur eingebaute Funktionen
  • nur eine Codezeile

Nachteil:

  • Möglicherweise gibt es effizientere Möglichkeiten, dies zu tun

Beispiel:

byte[] bytes = new byte[8];
Random r = new Random();
System.out.println("big-endian       | two's-complement");
System.out.println("-----------------|-----------------");
for (int i = 0; i < 10; i++) {
    r.nextBytes(bytes);
    System.out.print(String.format("%016X", new BigInteger(1,bytes)));
    System.out.print(" | ");
    System.out.print(String.format("%016X", new BigInteger(bytes)));
    System.out.println();
}

Beispielausgabe:

big-endian       | two's-complement
-----------------|-----------------
3971B56BC7C80590 | 3971B56BC7C80590
64D3C133C86CCBDC | 64D3C133C86CCBDC
B232EFD5BC40FA61 | -4DCD102A43BF059F
CD350CC7DF7C9731 | -32CAF338208368CF
82CDC9ECC1BC8EED | -7D3236133E437113
F438C8C34911A7F5 | -BC7373CB6EE580B
5E99738BE6ACE798 | 5E99738BE6ACE798
A565FE5CE43AA8DD | -5A9A01A31BC55723
032EBA783D2E9A9F | 032EBA783D2E9A9F
8FDAA07263217ABA | -70255F8D9CDE8546
Jan Martin Keil
quelle
-2

Verwenden

Integer.toHexString((int)b);
Juriy
quelle
Es gibt keine extra führenden Nullen!
user1722245