Articles

Converteren tussen Byte Arrays en Hexadecimale Strings in Java

Overzicht

In deze tutorial bekijken we de verschillende manieren om een byte array te converteren naar een hexadecimale String, en vice versa.

We zullen ook het conversiemechanisme begrijpen en onze implementatie schrijven om dit te bereiken.

Omzetten tussen Byte en Hexadecimaal

Laten we eerst eens kijken naar de conversielogica tussen byte- en hexadecimale getallen.

2.1. Byte naar hexadecimaal

De bytes zijn 8 bit getekende gehele getallen in Java. Daarom moeten we elk 4-bit segment apart omzetten naar hexadecimaal en ze aan elkaar koppelen. Na conversie krijgen we dan twee hexadecimale tekens.

Voorbeeld, we kunnen 45 in binair schrijven als 0010 1101, en het hexadecimale equivalent zal “2d” zijn:

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

Laten we deze eenvoudige logica in Java implementeren:

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

Nu, laten we de bovenstaande code begrijpen door elke operatie te analyseren. Allereerst hebben we een char array van lengte 2 gemaakt om de uitvoer in op te slaan:

char hexDigits = new char;

Daarna hebben we bits van hogere orde geïsoleerd door 4 bits naar rechts te verschuiven. En daarna hebben we een masker toegepast om de lagere 4 bits te isoleren. Het maskeren is nodig omdat negatieve getallen intern worden weergegeven als het complement van twee van het positieve getal:

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

Daarna converteren we de resterende 4 bits naar hexadecimaal:

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

Ten slotte maken we een String object van de char array. En vervolgens geven we dit object terug als geconverteerde hexadecimale array.

Nu gaan we begrijpen hoe dit werkt voor een negatieve byte -4:

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)

Het is ook de moeite waard om op te merken dat de Character.forDigit() methode altijd kleine letters retourneert.

2.2. Hexadecimaal naar byte

Nu gaan we een hexadecimaal cijfer omzetten naar een byte. Zoals we weten, bevat een byte 8 bits. Daarom hebben we twee hexadecimale cijfers nodig om één byte te maken.

Op de eerste plaats zetten we elk hexadecimaal cijfer afzonderlijk om in een binair equivalent.

En dan moeten we de twee vier bitsegmenten samenvoegen om het byte-equivalent te krijgen:

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

Nu, laten we de bewerking in Java schrijven:

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

Laten we dit eens begrijpen, één bewerking tegelijk.

Eerst hebben we hexadecimale tekens omgezet in gehele getallen:

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

Daarna hebben we het meest significante cijfer met 4 bits naar links verschoven. Als gevolg daarvan heeft de binaire representatie nullen op vier minst significante bits.

Daarna hebben we het minst significante cijfer toegevoegd:

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

Nu, laten we de toDigit() methode eens goed bekijken. We gebruiken de Character.digit() methode voor de conversie. Als de tekenwaarde die aan deze methode wordt doorgegeven geen geldig cijfer in de opgegeven radix is, wordt -1 teruggegeven.

We valideren de teruggegeven waarde en gooien een exceptie als een ongeldige waarde is doorgegeven.

Omzetten tussen Byte-arrays en Hexadecimale strings

Op dit punt weten we hoe we een byte naar hexadecimaal moeten converteren, en omgekeerd. Laten we dit algoritme uitbreiden en byte-arrays converteren naar/van hexadecimale strings.

3.1. Byte Array naar Hexadecimale String

We moeten de array doorlopen en voor elke byte een hexadecimaal paar genereren:

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

Zoals we al weten, zal de uitvoer altijd in kleine letters zijn.

3.2. Hexadecimale String naar Byte Array

Eerst moeten we controleren of de lengte van de hexadecimale String een even getal is. Dit is omdat een hexadecimale String met een oneven lengte zal resulteren in een onjuiste byte representatie.

Nu zullen we door de array itereren en elk hexadecimaal paar converteren naar een byte:

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

Gebruik de BigInteger Class

We kunnen een object van het type BigInteger maken door een signum en byte array door te geven.

Nu kunnen we de hexadecimale String genereren met behulp van de statische methode format gedefinieerd in de String klasse:

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

Het geboden format genereert een hexadecimale String met kleine letters en een vulling van nul. We kunnen ook een hoofdletter string genereren door “x” te vervangen door “X”.

Als alternatief hadden we ook de toString() methode van BigInteger kunnen gebruiken. Het subtiele verschil van het gebruik van de methode toString() is dat de uitvoer niet wordt opgevuld met voorloopnullen:

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

Nu gaan we eens kijken naar de hexadecimale String naar byte Array conversie:

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

De methode toByteArray() produceert een extra tekenbit. We hebben specifieke code geschreven voor het omgaan met deze extra bit.

Daarom moeten we ons bewust zijn van deze details voordat we de BigInteger klasse gebruiken voor de conversie.

Gebruik van de DataTypeConverter klasse

De DataTypeConverter klasse wordt geleverd met de JAXB bibliotheek. Deze maakt deel uit van de standaard bibliotheek tot Java 8. Vanaf Java 9, moeten we java.xml.bind module expliciet toevoegen aan de runtime.

Laten we eens kijken naar de implementatie met behulp van de DataTypeConverter klasse:

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

Zoals hierboven weergegeven, is het erg handig om de DataTypeConverter klasse te gebruiken. De uitvoer van de printHexBinary() methode is altijd in hoofdletters. Deze klasse levert een set van print en parse methoden voor datatype conversie.

Voordat we voor deze aanpak kiezen, moeten we er zeker van zijn dat de klasse beschikbaar zal zijn tijdens runtime.

Gebruik Apache’s Commons-codec-bibliotheek

We kunnen de Hex-klasse gebruiken die wordt geleverd met de Apache commons-codec-bibliotheek:

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

De uitvoer van encodeHexString is altijd in kleine letters.

Gebruik Google’s Guava Library

Laten we eens kijken hoe de BaseEncoding klasse kan worden gebruikt voor het coderen en decoderen van byte array naar de hexadecimale String:

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

De BaseEncoding codeert en decodeert standaard met gebruikmaking van hoofdletters. Als we kleine letters willen gebruiken, moet een nieuwe codeerinstantie worden gemaakt met de statische methode lowercase.

Conclusie

In dit artikel hebben we het conversiealgoritme tussen byte-array en hexadecimale String geleerd. We hebben ook verschillende methoden besproken om byte array naar hexadecimale string te coderen en vice versa.

Het wordt niet aangeraden om een bibliotheek toe te voegen om alleen een paar utility methoden te gebruiken. Daarom, als we de externe bibliotheken nog niet gebruiken, moeten we het besproken algoritme gebruiken. De DataTypeConverter klasse is een andere manier om te coderen/decoderen tussen verschillende gegevenstypen.

Laat een antwoord achter

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *