Java >> Java tutorial >  >> Tag >> byte

Konvertering mellem byte-arrays og hexadecimale strenge i Java

1. Oversigt

I denne øvelse tager vi et kig på forskellige måder at konvertere en byte-array til en hexadecimal streng, og omvendt.

Vi vil også forstå konverteringsmekanismen og skrive vores implementering for at opnå dette.

2. Konvertering mellem byte og hexadecimal

Lad os først og fremmest tage et kig på konverteringslogikken mellem byte og hexadecimale tal.

2.1. Byte til hexadecimal

Bytene er 8 bit signerede heltal i Java. Derfor er vi nødt til at konvertere hvert 4-bit segment til hex separat og sammenkæde dem . Derfor får vi to hexadecimale tegn efter konvertering.

For eksempel kan vi skrive 45 som 0010 1101 i binær, og den hexadecimale ækvivalent vil være "2d":

0010 = 2 (base 10) = 2 (base 16)
1101 = 13 (base 10) = d (base 16)

Therefore: 45 = 0010 1101 = 0x2d

Lad os implementere denne enkle logik i Java:

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

Lad os nu forstå ovenstående kode ved at analysere hver operation. Først og fremmest oprettede vi et char-array med længde 2 for at gemme outputtet:

char[] hexDigits = new char[2];

Dernæst isolerede vi højere ordens bits ved at højreforskyde 4 bits. Og så anvendte vi en maske for at isolere lavere ordens 4 bits. Maskering er påkrævet, fordi negative tal internt repræsenteres som tos komplement til det positive tal:

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

Så konverterer vi de resterende 4 bits til hexadecimal:

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

Til sidst opretter vi en streng objekt fra char-arrayet. Og returnerede derefter dette objekt som konverteret hexadecimal array.

Lad os nu forstå, hvordan dette vil fungere for en negativ byte -4:

hexDigits[0]:
1111 1100 >> 4 = 1111 1111 1111 1111 1111 1111 1111 1111
1111 1111 1111 1111 1111 1111 1111 1111 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1111 = 0xf

hexDigits[1]:
1111 1100 & 0xF = 0000 1100 = 0xc

Therefore: -4 (base 10) = 1111 1100 (base 2) = fc (base 16)

Det er også værd at bemærke, at Karakteren. for Digit() metode returnerer altid små bogstaver.

2.2. Hexadecimal til byte

Lad os nu konvertere et hexadecimalt ciffer til byte. Som vi ved, indeholder en byte 8 bits. Derfor vi har brug for to hexadecimale cifre for at skabe én byte .

Først og fremmest konverterer vi hvert hexadecimalt ciffer til binære ækvivalenter separat.

Og så skal vi sammenkæde de to fire bit-segmenter for at få byte-ækvivalenten:

Hexadecimal: 2d
2 = 0010 (base 2)
d = 1101 (base 2)

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

Lad os nu skrive operationen i 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;
}

Lad os forstå dette, en operation ad gangen.

Først og fremmest konverterede vi hexadecimale tegn til heltal:

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

Så forlod vi det mest signifikante ciffer med 4 bit. Følgelig har den binære repræsentation nuller ved fire mindst signifikante bits.

Derefter føjede vi det mindst signifikante ciffer til det:

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

Lad os nu undersøge toDigit() metode tæt på. Vi bruger Character.digit() metode til konvertering. Hvis tegnværdien, der sendes til denne metode, ikke er et gyldigt ciffer i den angivne radix, returneres -1.

Vi validerer returværdien og afgiver en undtagelse, hvis en ugyldig værdi blev godkendt.

3. Konvertering mellem byte-arrays og hexadecimale strenge

På dette tidspunkt ved vi, hvordan man konverterer en byte til hexadecimalen og omvendt. Lad os skalere denne algoritme og konvertere byte-array til/fra hexadecimal streng .

3.1. Byte Array til Hexadecimal String

Vi skal sløjfe gennem arrayet og generere hexadecimalt par for hver byte:

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

Som vi allerede ved, vil output altid være med små bogstaver.

3.2. Hexadecimal streng til byte-array

Først og fremmest skal vi kontrollere, om længden af ​​den hexadecimale streng er et lige tal. Dette skyldes, at en hexadecimal streng med ulige længde vil resultere i forkert byte-repræsentation.

Nu vil vi iterere gennem arrayet og konvertere hvert hexadecimalt par til en byte:

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

4. Brug af BigInteger Klasse

Vi kan oprette et objekt af typen BigInteger ved at sende et signum og byte-array .

Nu kan vi generere den hexadecimale streng ved hjælp af statisk metodeformat defineret i String klasse:

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

Det angivne format vil generere en nulpolstret hexadecimal streng. Vi kan også generere en streng med store bogstaver ved at erstatte "x" med "X".

Alternativt kunne vi have brugt toString() metode fra BigInteger . Den subtile forskel ved at bruge toString() metode er, at outputtet ikke er polstret med foranstillede nuller :

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

Lad os nu tage et kig på hexadecimal streng til byte Konvertering af matrix:

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

toByteArray() metode producerer en ekstra tegnbit . Vi har skrevet specifik kode til at håndtere denne ekstra bit.

Derfor bør vi være opmærksomme på disse detaljer, før vi bruger BigInteger klasse for konverteringen.

5. Brug af DataTypeConverter Klasse

DataTypeConverter klasse leveres med JAXB bibliotek. Dette er en del af standardbiblioteket indtil Java 8. Fra Java 9 skal vi tilføje java.xml.bind modul til runtime eksplicit.

Lad os tage et kig på implementering ved hjælp af DataTypeConverter klasse:

public String encodeUsingDataTypeConverter(byte[] bytes) {
    return DatatypeConverter.printHexBinary(bytes);
}

public byte[] decodeUsingDataTypeConverter(String hexString) {
    return DatatypeConverter.parseHexBinary(hexString);
}

Som vist ovenfor er det meget praktisk at bruge DataTypeConverter klasse. outputtet fra printHexBinary() metode er altid med store bogstaver . Denne klasse leverer et sæt print- og parsemetoder til datatypekonvertering.

Før vi vælger denne tilgang, skal vi sikre os, at klassen er tilgængelig under kørsel.

6. Brug af Apaches Commons-Codec Library

Vi kan bruge Hex klasse, der følger med Apache commons-codec-biblioteket:

public String encodeUsingApacheCommons(byte[] bytes) 
  throws DecoderException {
    return Hex.encodeHexString(bytes);
}

public byte[] decodeUsingApacheCommons(String hexString) 
  throws DecoderException {
    return Hex.decodeHex(hexString);
}

outputtet fra encodeHexString er altid med små bogstaver .

7. Brug af Googles Guava-bibliotek

Lad os tage et kig på, hvordan BaseEncoding klasse kan bruges til kodning og afkodning af byte-array til den hexadecimale String:

public String encodeUsingGuava(byte[] bytes) {
    return BaseEncoding.base16().encode(bytes);
}

public byte[] decodeUsingGuava(String hexString) {
    return BaseEncoding.base16()
      .decode(hexString.toUpperCase());
}

BaseEncoding koder og afkoder ved hjælp af store bogstaver som standard . Hvis vi skal bruge små bogstaver, skal der oprettes en ny indkodningsinstans ved hjælp af den statiske metode med små bogstaver.

8. Konklusion

I denne artikel lærte vi konverteringsalgoritmen mellem byte-array til hexadecimal String . Vi diskuterede også forskellige metoder til at kode byte-array til hex-streng og omvendt.

Det anbefales ikke at tilføje et bibliotek for kun at bruge et par hjælpemetoder. Derfor, hvis vi ikke allerede bruger de eksterne biblioteker, bør vi bruge den diskuterede algoritme. DataTypeConverter klasse er en anden måde at indkode/afkode mellem forskellige datatyper.

Endelig er den komplette kildekode til denne tutorial tilgængelig på GitHub.


Java tag