Articles

Konvertieren zwischen Byte-Arrays und hexadezimalen Strings in Java

Übersicht

In diesem Tutorial sehen wir uns verschiedene Möglichkeiten an, ein Byte-Array in einen hexadezimalen String zu konvertieren und umgekehrt.

Wir werden auch den Konvertierungsmechanismus verstehen und unsere Implementierung schreiben, um dies zu erreichen.

Konvertieren zwischen Byte und Hexadezimal

Zunächst wollen wir einen Blick auf die Konvertierungslogik zwischen Byte- und Hexadezimalzahlen werfen.

2.1. Byte zu Hexadezimal

Die Bytes sind in Java 8-Bit-Ganzzahlen mit Vorzeichen. Daher müssen wir jedes 4-Bit-Segment separat in Hexadezimal umwandeln und aneinanderhängen. Folglich erhalten wir nach der Konvertierung zwei hexadezimale Zeichen.

Zum Beispiel können wir 45 als 0010 1101 im Binärformat schreiben, und das hexadezimale Äquivalent wird „2d“ sein:

0010 = 2 (base 10) = 2 (base 16)1101 = 13 (base 10) = d (base 16)Therefore: 45 = 0010 1101 = 0x2d

Lassen Sie uns diese einfache Logik in Java implementieren:

public String byteToHex(byte num) { char hexDigits = new char; hexDigits = Character.forDigit((num >> 4) & 0xF, 16); hexDigits = Character.forDigit((num & 0xF), 16); return new String(hexDigits);}

Nun, lassen Sie uns den obigen Code verstehen, indem wir jede Operation analysieren. Zuerst haben wir ein char-Array der Länge 2 erstellt, um die Ausgabe zu speichern:

char hexDigits = new char;

Nächstens haben wir Bits höherer Ordnung isoliert, indem wir 4 Bits nach rechts verschoben haben. Und dann haben wir eine Maske angewendet, um die 4 Bits niedrigerer Ordnung zu isolieren. Die Maskierung ist erforderlich, weil negative Zahlen intern als Zweierkomplement der positiven Zahl dargestellt werden:

hexDigits = Character.forDigit((num >> 4) & 0xF, 16);

Dann wandeln wir die restlichen 4 Bits in Hexadezimal um:

hexDigits = Character.forDigit((num & 0xF), 16);

Schließlich erstellen wir ein String-Objekt aus dem Char-Array. Und geben dann dieses Objekt als konvertiertes Hexadezimal-Array zurück.

Nun wollen wir verstehen, wie das bei einem negativen Byte -4 funktioniert:

hexDigits:1111 1100 >> 4 = 1111 1111 1111 1111 1111 1111 1111 11111111 1111 1111 1111 1111 1111 1111 1111 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1111 = 0xfhexDigits:1111 1100 & 0xF = 0000 1100 = 0xcTherefore: -4 (base 10) = 1111 1100 (base 2) = fc (base 16)

Es ist auch erwähnenswert, dass die Methode Character.forDigit() immer Kleinbuchstaben zurückgibt.

2.2. Hexadezimal zu Byte

Nun wollen wir eine hexadezimale Ziffer in ein Byte umwandeln. Wie wir wissen, enthält ein Byte 8 Bits. Daher benötigen wir zwei Hexadezimalziffern, um ein Byte zu erzeugen.

Zunächst wandeln wir jede Hexadezimalziffer einzeln in die binäre Entsprechung um.

Und dann müssen wir die beiden Vier-Bit-Segmente verketten, um das Byte-Äquivalent zu erhalten:

Hexadecimal: 2d2 = 0010 (base 2)d = 1101 (base 2)Therefore: 2d = 0010 1101 (base 2) = 45

Nun schreiben wir die Operation in Java:

public byte hexToByte(String hexString) { int firstDigit = toDigit(hexString.charAt(0)); int secondDigit = toDigit(hexString.charAt(1)); return (byte) ((firstDigit << 4) + secondDigit);}private int toDigit(char hexChar) { int digit = Character.digit(hexChar, 16); if(digit == -1) { throw new IllegalArgumentException( "Invalid Hexadecimal Character: "+ hexChar); } return digit;}

Lassen Sie uns das verstehen, eine Operation nach der anderen.

Zunächst haben wir hexadezimale Zeichen in ganze Zahlen umgewandelt:

int firstDigit = toDigit(hexString.charAt(0));int secondDigit = toDigit(hexString.charAt(1));

Dann haben wir die höchstwertige Stelle um 4 Bits nach links verschoben. Folglich hat die binäre Darstellung Nullen an den vier niederwertigsten Bits.

Dann haben wir die niederwertigste Ziffer hinzugefügt:

return (byte) ((firstDigit << 4) + secondDigit);

Nun wollen wir uns die Methode toDigit() genauer ansehen. Wir verwenden die Methode Character.digit() zur Konvertierung. Wenn der an diese Methode übergebene Zeichenwert keine gültige Ziffer in der angegebenen Radix ist, wird -1 zurückgegeben.

Wir validieren den Rückgabewert und werfen eine Exception, wenn ein ungültiger Wert übergeben wurde.

Konvertieren zwischen Byte-Arrays und Hexadezimal-Strings

An dieser Stelle wissen wir, wie man ein Byte in den Hexadezimalbereich konvertiert und umgekehrt. Lassen Sie uns diesen Algorithmus skalieren und Byte-Array in/aus hexadezimaler Zeichenkette konvertieren.

3.1. Byte-Array zu Hexadezimal-String

Wir müssen durch das Array schleifen und für jedes Byte ein Hexadezimal-Paar erzeugen:

public String encodeHexString(byte byteArray) { StringBuffer hexStringBuffer = new StringBuffer(); for (int i = 0; i < byteArray.length; i++) { hexStringBuffer.append(byteToHex(byteArray)); } return hexStringBuffer.toString();}

Wie wir bereits wissen, wird die Ausgabe immer in Kleinbuchstaben erfolgen.

3.2. Hexadezimaler String zu Byte-Array

Zunächst müssen wir prüfen, ob die Länge des hexadezimalen Strings eine gerade Zahl ist. Denn ein hexadezimaler String mit ungerader Länge führt zu einer falschen Byte-Darstellung.

Nun iterieren wir durch das Array und wandeln jedes hexadezimale Paar in ein Byte um:

public byte decodeHexString(String hexString) { if (hexString.length() % 2 == 1) { throw new IllegalArgumentException( "Invalid hexadecimal String supplied."); } byte bytes = new byte; for (int i = 0; i < hexString.length(); i += 2) { bytes = hexToByte(hexString.substring(i, i + 2)); } return bytes;}

Verwendung der BigInteger-Klasse

Wir können ein Objekt vom Typ BigInteger erzeugen, indem wir ein Signum und ein Byte-Array übergeben.

Nun können wir den hexadezimalen String mit Hilfe der statischen Methode format, die in der Klasse String definiert ist, erzeugen:

public String encodeUsingBigIntegerStringFormat(byte bytes) { BigInteger bigInteger = new BigInteger(1, bytes); return String.format( "%0" + (bytes.length << 1) + "x", bigInteger);}

Das bereitgestellte Format erzeugt einen mit Nullen aufgefüllten klein geschriebenen hexadezimalen String. Wir können auch einen String in Großbuchstaben erzeugen, indem wir „x“ durch „X“ ersetzen.

Alternativ hätten wir auch die Methode toString() von BigInteger verwenden können. Der feine Unterschied bei der Verwendung der toString()-Methode ist, dass die Ausgabe nicht mit führenden Nullen aufgefüllt wird:

public String encodeUsingBigIntegerToString(byte bytes) { BigInteger bigInteger = new BigInteger(1, bytes); return bigInteger.toString(16);}

Werfen wir nun einen Blick auf die Konvertierung von hexadezimalen Strings in Byte-Arrays:

public byte decodeUsingBigInteger(String hexString) { byte byteArray = new BigInteger(hexString, 16) .toByteArray(); if (byteArray == 0) { byte output = new byte; System.arraycopy( byteArray, 1, output, 0, output.length); return output; } return byteArray;}

Die toByteArray()-Methode erzeugt ein zusätzliches Vorzeichenbit. Wir haben speziellen Code für die Behandlung dieses zusätzlichen Bits geschrieben.

Daher sollten wir uns dieser Details bewusst sein, bevor wir die BigInteger-Klasse für die Konvertierung verwenden.

Verwendung der DataTypeConverter-Klasse

Die DataTypeConverter-Klasse wird mit der JAXB-Bibliothek geliefert. Diese ist bis Java 8 Teil der Standardbibliothek. Ab Java 9 müssen wir das Modul java.xml.bind explizit zur Laufzeit hinzufügen.

Lassen Sie uns einen Blick auf die Implementierung mit der DataTypeConverter-Klasse werfen:

public String encodeUsingDataTypeConverter(byte bytes) { return DatatypeConverter.printHexBinary(bytes);}public byte decodeUsingDataTypeConverter(String hexString) { return DatatypeConverter.parseHexBinary(hexString);}

Wie oben dargestellt, ist es sehr bequem, die DataTypeConverter-Klasse zu verwenden. Die Ausgabe der Methode printHexBinary() erfolgt immer in Großbuchstaben. Diese Klasse liefert einen Satz von print- und parse-Methoden für die Datentypkonvertierung.

Bevor wir diesen Ansatz wählen, müssen wir sicherstellen, dass die Klasse zur Laufzeit verfügbar ist.

Verwendung der Apache Commons-Codec-Bibliothek

Wir können die Hex-Klasse verwenden, die mit der Apache Commons-Codec-Bibliothek geliefert wird:

public String encodeUsingApacheCommons(byte bytes) throws DecoderException { return Hex.encodeHexString(bytes);}public byte decodeUsingApacheCommons(String hexString) throws DecoderException { return Hex.decodeHex(hexString);}

Die Ausgabe von encodeHexString ist immer in Kleinbuchstaben.

Verwendung der Guava-Bibliothek von Google

Schauen wir uns an, wie die Klasse BaseEncoding zum Kodieren und Dekodieren von Byte-Arrays in den hexadezimalen String verwendet werden kann:

public String encodeUsingGuava(byte bytes) { return BaseEncoding.base16().encode(bytes);}public byte decodeUsingGuava(String hexString) { return BaseEncoding.base16() .decode(hexString.toUpperCase());}

Die BaseEncoding kodiert und dekodiert standardmäßig mit Großbuchstaben. Wenn wir Kleinbuchstaben verwenden müssen, sollte eine neue Encoding-Instanz mit der statischen Methode lowercase erstellt werden.

Abschluss

In diesem Artikel haben wir den Konvertierungsalgorithmus zwischen Byte-Array und hexadezimalem String kennengelernt. Wir haben auch verschiedene Methoden besprochen, um Byte-Array in Hexadezimal-String zu kodieren und umgekehrt.

Es ist nicht ratsam, eine Bibliothek hinzuzufügen, nur um ein paar Utility-Methoden zu verwenden. Daher sollten wir, wenn wir die externen Bibliotheken nicht bereits verwenden, den besprochenen Algorithmus verwenden. Die Klasse DataTypeConverter ist eine weitere Möglichkeit, zwischen verschiedenen Datentypen zu kodieren/dekodieren.

Eine Antwort schreiben

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.