Konvertieren einer Zeichenfolgendarstellung eines Hex-Dumps mit Java in ein Byte-Array?

372

Ich suche nach einer Möglichkeit, eine lange Zeichenfolge (aus einem Speicherauszug), die Hex-Werte darstellt, in ein Byte-Array umzuwandeln.

Ich hätte es nicht besser formulieren können als die Person, die hier dieselbe Frage gestellt hat .

Aber um es original zu halten, werde ich es auf meine eigene Weise formulieren: Angenommen, ich habe eine Zeichenfolge "00A0BF", die ich gerne als die interpretieren würde

byte[] {0x00,0xA0,0xBf}

was sollte ich tun?

Ich bin ein Java-Neuling und habe am Ende BigIntegerführende Hex-Nullen verwendet und darauf geachtet. Aber ich finde es hässlich und ich bin mir sicher, dass mir etwas Einfaches fehlt.

Rafraf
quelle
Ich habe BigInteger hier gezähmt .
John McClane
FWIW funktioniert String.getBytes()nicht so, wie Sie es sich vorstellen . Musste das auf die harte Tour lernen. if ("FF".getBytes() != "ff".getBytes()) { System.out.println("Try again"); }
Tir38

Antworten:

636

Hier ist eine Lösung, die meiner Meinung nach besser ist als jede bisher veröffentlichte:

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

Gründe, warum es eine Verbesserung ist:

  • Sicher mit führenden Nullen (im Gegensatz zu BigInteger) und mit negativen Bytewerten (im Gegensatz zu Byte.parseByte)

  • Konvertiert den String nicht in ein char[]oder erstellt StringBuilder- und String-Objekte für jedes einzelne Byte.

  • Keine Bibliotheksabhängigkeiten, die möglicherweise nicht verfügbar sind

Sie können die Argumentprüfung über assertoder Ausnahmen hinzufügen, wenn nicht bekannt ist, dass das Argument sicher ist.

Dave L.
quelle
2
Können Sie ein falsch dekodiertes Beispiel nennen oder erklären, wie es falsch ist?
Dave L.
5
Es funktioniert nicht für den String "0". Es
löst
49
"0" ist keine gültige Eingabe. Bytes erfordern jeweils zwei hexadezimale Ziffern. In der Antwort heißt es: "Fühlen Sie sich frei, eine Argumentprüfung hinzuzufügen ... wenn nicht bekannt ist, dass das Argument sicher ist."
Dave L.
12
javax.xml.bind.DatatypeConverter.parseHexBinary (hexString) scheint in meinen Mikrotests etwa 20% schneller zu sein als die oben genannte Lösung (für was auch immer sie wert sind) und Ausnahmen für ungültige Eingaben korrekt auszulösen (z. B. "gg"). ist kein gültiger hexString, gibt aber -77 zurück, wenn die vorgeschlagene Lösung verwendet wird.
Trevor Freeman
6
@DaedalusAlpha Es hängt von Ihrem Kontext ab, aber normalerweise finde ich es besser, schnell und laut mit solchen Dingen zu scheitern, damit Sie Ihre Annahmen korrigieren können, anstatt stillschweigend falsche Daten zurückzugeben.
Dave L.
331

Einzeiler:

import javax.xml.bind.DatatypeConverter;

public static String toHexString(byte[] array) {
    return DatatypeConverter.printHexBinary(array);
}

public static byte[] toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s);
}

Warnungen :

  • In Java 9 Jigsaw ist dies nicht mehr Teil des (Standard-) java.se-Stammsatzes, sodass eine ClassNotFoundException ausgelöst wird, sofern Sie nicht --add-modules java.se.ee angeben (danke an @ eckes).
  • Nicht verfügbar für Android (danke Fabiandafür), aber Sie können einfach den Quellcode verwenden, wenn Ihr System javax.xmlaus irgendeinem Grund fehlt . Vielen Dank an @ Bert Regelinkfür das Extrahieren der Quelle.
Vladislav Rastrusny
quelle
14
IMHO sollte dies die akzeptierte / Top-Antwort sein, da sie kurz und sauber ist (im Gegensatz zu @ DaveLs Antwort) und keine externen Bibliotheken erfordert (wie die Antwort von Skaffman). Außerdem: <Geben Sie einen abgenutzten Witz über die Neuerfindung des Fahrrads ein> .
Priidu Neemre
9
Die Datentyp-Konverter-Klasse ist beispielsweise in Android nicht verfügbar.
Fabian
4
Warnung: In Java 9 Jigsaw ist dies nicht mehr Teil des (Standard-) java.seClassNotFoundException--add-modules java.se.ee
Stammsatzes
2
@dantebarba Ich denke, es gibt javax.xml.bind.DatatypeConverterbereits eine Methode zum Codieren / Decodieren von Base64-Daten. Siehe parseBase64Binary()und printBase64Binary().
DragShot
2
So fügen Sie auf die Fragen mit DataTypeConverter, 11 Java SE hat die JAXB API vollständig entfernt und ist jetzt nur mit Java EE enthalten. Sie können es auch als Maven-Abhängigkeit hinzufügen, wie hier vorgeschlagen: stackoverflow.com/a/43574427/7347751
David Mordigal
79

Die Hex-Klasse im Commons-Codec sollte das für Sie tun.

http://commons.apache.org/codec/

import org.apache.commons.codec.binary.Hex;
...
byte[] decoded = Hex.decodeHex("00A0BF");
// 0x00 0xA0 0xBF
Skaffman
quelle
6
Das sieht auch gut aus. Siehe org.apache.commons.codec.binary.Hex.decodeHex ()
Dave L.
Es war interessant. Aber ich fand ihre Lösung schwer zu folgen. Hat es irgendwelche Vorteile gegenüber dem, was Sie vorgeschlagen haben (außer nach einer geraden Anzahl von Zeichen zu suchen)?
Rafraf
38

Sie können jetzt BaseEncoding in verwenden guava, um dies zu erreichen.

BaseEncoding.base16().decode(string);

Um es umzukehren, verwenden Sie

BaseEncoding.base16().encode(bytes);
jontro
quelle
27

Eigentlich finde ich die BigInteger-Lösung sehr schön:

new BigInteger("00A0BF", 16).toByteArray();

Bearbeiten: Nicht sicher für führende Nullen , wie auf dem Poster angegeben.

Dave L.
quelle
Das habe ich mir auch anfangs gedacht. Und danke, dass Sie es dokumentiert haben - ich dachte nur, ich sollte ... es hat einige seltsame Dinge getan, die ich nicht wirklich verstanden habe - wie das Weglassen von führenden 0x00 und das Verwechseln der Reihenfolge von 1 Byte in einer 156-Byte-Zeichenfolge I. spielte mit.
Rafraf
2
Das ist ein guter Punkt, um Nullen zu führen. Ich bin mir nicht sicher, ob ich glaube, dass es die Reihenfolge der Bytes verwechseln könnte, und wäre sehr interessiert, wenn es demonstriert würde.
Dave L.
1
Ja, sobald ich es gesagt habe, habe ich mir auch nicht geglaubt :) Ich habe einen Vergleich des Byte-Arrays von BigInteger mit mmyers'fromHexString und (ohne 0x00) mit der fehlerhaften Zeichenfolge durchgeführt - sie waren identisch. Die "Verwechslung" ist passiert, aber es könnte etwas anderes gewesen sein. Ich werde morgen genauer hinsehen
Rafraf
3
Das Problem mit BigInteger ist, dass es ein "Vorzeichenbit" geben muss. Wenn für das führende Byte das High-Bit gesetzt ist, hat das resultierende Byte-Array an der 1. Position eine zusätzliche 0. Aber immer noch +1.
Grau
25

Einzeiler:

import javax.xml.bind.DatatypeConverter;

public static String toHexString(byte[] array) {
    return DatatypeConverter.printHexBinary(array);
}

public static byte[] toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s);
}

Für diejenigen unter Ihnen, die sich für den eigentlichen Code hinter den Einzeilern von FractalizeR interessieren (ich brauchte das, da javax.xml.bind für Android nicht verfügbar ist (standardmäßig)), kommt dieser von com.sun.xml.internal.bind. DatatypeConverterImpl.java :

public byte[] parseHexBinary(String s) {
    final int len = s.length();

    // "111" is not a valid hex encoding.
    if( len%2 != 0 )
        throw new IllegalArgumentException("hexBinary needs to be even-length: "+s);

    byte[] out = new byte[len/2];

    for( int i=0; i<len; i+=2 ) {
        int h = hexToBin(s.charAt(i  ));
        int l = hexToBin(s.charAt(i+1));
        if( h==-1 || l==-1 )
            throw new IllegalArgumentException("contains illegal character for hexBinary: "+s);

        out[i/2] = (byte)(h*16+l);
    }

    return out;
}

private static int hexToBin( 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 char[] hexCode = "0123456789ABCDEF".toCharArray();

public String printHexBinary(byte[] data) {
    StringBuilder r = new StringBuilder(data.length*2);
    for ( byte b : data) {
        r.append(hexCode[(b >> 4) & 0xF]);
        r.append(hexCode[(b & 0xF)]);
    }
    return r.toString();
}
Bert Regelink
quelle
3
DatatypeConverter ist in Java 9 standardmäßig auch nicht verfügbar. Das Gefährliche ist, dass Code, der ihn verwendet, unter Java 1.8 oder früher kompiliert wird (Java 9 mit Quelleinstellungen auf früher), aber unter Java 9 eine Laufzeitausnahme ohne "--add-modules java.se.ee" erhält.
Stephen M-auf Streik-
24

Das HexBinaryAdapterbietet die Möglichkeit, zwischen Stringund zu marshallen und zu marshallen byte[].

import javax.xml.bind.annotation.adapters.HexBinaryAdapter;

public byte[] hexToBytes(String hexString) {
     HexBinaryAdapter adapter = new HexBinaryAdapter();
     byte[] bytes = adapter.unmarshal(hexString);
     return bytes;
}

Das ist nur ein Beispiel, das ich eingegeben habe ... Ich verwende es einfach so wie es ist und muss keine separate Methode für die Verwendung erstellen.

GrkEngineer
quelle
5
Dies funktioniert nur, wenn die Eingabezeichenfolge (hexString) eine gerade Anzahl von Zeichen enthält. Andernfalls: Ausnahme im Thread "main" java.lang.IllegalArgumentException: hexBinary muss gerade sein:
ovdsrn
3
Oh, danke, dass du darauf hingewiesen hast. Ein Benutzer sollte wirklich keine ungerade Anzahl von Zeichen haben, da das Byte-Array als {0x00,0xA0,0xBf} dargestellt wird. Jedes Byte hat zwei hexadezimale Ziffern oder Halbbytes. Daher sollte eine beliebige Anzahl von Bytes immer eine gerade Anzahl von Zeichen haben. Vielen Dank, dass Sie dies erwähnt haben.
GrkEngineer
8
Sie können java.xml.bind.DatatypeConverter.parseHexBinary (hexString) direkt verwenden, anstatt HexBinaryAdapter (der wiederum DatatypeConverter aufruft) zu verwenden. Auf diese Weise müssen Sie kein Adapterinstanzobjekt erstellen (da DatatypeConverter-Methoden statisch sind).
Trevor Freeman
javax.xml.bind. * 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 Quelleinstellungen auf früher), aber eine Laufzeitausnahme unter Java 9 erhält.
Stephen M-auf Streik-
15

Hier ist eine Methode, die tatsächlich funktioniert (basierend auf mehreren vorherigen halbkorrekten Antworten):

private static byte[] fromHexString(final String encoded) {
    if ((encoded.length() % 2) != 0)
        throw new IllegalArgumentException("Input string must contain an even number of characters");

    final byte result[] = new byte[encoded.length()/2];
    final char enc[] = encoded.toCharArray();
    for (int i = 0; i < enc.length; i += 2) {
        StringBuilder curr = new StringBuilder(2);
        curr.append(enc[i]).append(enc[i + 1]);
        result[i/2] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    return result;
}

Das einzig mögliche Problem, das ich sehen kann, ist, ob die Eingabezeichenfolge extrem lang ist. Durch Aufrufen von toCharArray () wird eine Kopie des internen Arrays der Zeichenfolge erstellt.

EDIT: Oh, und übrigens, Bytes sind in Java signiert, also wird Ihre Eingabezeichenfolge in [0, -96, -65] anstelle von [0, 160, 191] konvertiert. Aber das wusstest du wahrscheinlich schon.

Michael Myers
quelle
1
Danke Michael - du bist ein Lebensretter! Arbeiten an einem BlackBerry-Projekt und versuchen, eine Zeichenfolgendarstellung eines Bytes wieder in das Byte zu konvertieren ... mit der RIM-Methode "Byte.parseByte (byteString, 16)". Habe eine NumberFormatExcpetion geworfen. Verbrachte Stunden damit, herauszufinden, warum. Ihr Vorschlag von "Integer.praseInt ()" hat es geschafft. Danke noch einmal!!
BonanzaDriver
12

In Android, wenn Sie mit Hex arbeiten, können Sie okio versuchen .

einfache Verwendung:

byte[] bytes = ByteString.decodeHex("c000060000").toByteArray();

und Ergebnis wird sein

[-64, 0, 6, 0, 0]
Miao1007
quelle
Ich habe viele verschiedene Methoden getestet, aber diese ist mindestens doppelt so schnell!
Poby
5

Die BigInteger()Methode von java.math ist sehr langsam und nicht empfehlenswert.

Integer.parseInt(HEXString, 16)

kann bei einigen Zeichen Probleme verursachen, ohne in Digit / Integer zu konvertieren

eine gut funktionierende Methode:

Integer.decode("0xXX") .byteValue()

Funktion:

public static byte[] HexStringToByteArray(String s) {
    byte data[] = new byte[s.length()/2];
    for(int i=0;i < s.length();i+=2) {
        data[i/2] = (Integer.decode("0x"+s.charAt(i)+s.charAt(i+1))).byteValue();
    }
    return data;
}

Viel Spaß, viel Glück

Scharfschütze
quelle
4

BEARBEITEN: Wie von @mmyers hervorgehoben, funktioniert diese Methode nicht bei Eingaben, die Teilzeichenfolgen enthalten, die Bytes mit gesetztem High-Bit ("80" - "FF") entsprechen. Die Erklärung finden Sie unter Fehler-ID: 6259307 Byte.parseByte funktioniert nicht wie in der SDK-Dokumentation angegeben .

public static final byte[] fromHexString(final String s) {
    byte[] arr = new byte[s.length()/2];
    for ( int start = 0; start < s.length(); start += 2 )
    {
        String thisByte = s.substring(start, start+2);
        arr[start/2] = Byte.parseByte(thisByte, 16);
    }
    return arr;
}
Blair Conrad
quelle
1
Schließen, aber diese Methode schlägt bei der angegebenen Eingabe "00A0BBF" fehl. Siehe bugs.sun.com/bugdatabase/view_bug.do?bug_id=6259307 .
Michael Myers
1
Seltsamerweise
1
@mmyers: whoa. Das ist nicht gut. Entschuldigung für die Verwirrung. @ravigad: 9C hat das gleiche Problem, da in diesem Fall das High-Bit gesetzt ist.
Blair Conrad
(Byte) Short.parseShort (thisByte, 16) löst dieses Problem
Jamey Hicks
3

Für das, was es wert ist, ist hier eine andere Version, die Zeichenfolgen mit ungerader Länge unterstützt, ohne auf die Verkettung von Zeichenfolgen zurückzugreifen.

public static byte[] hexStringToByteArray(String input) {
    int len = input.length();

    if (len == 0) {
        return new byte[] {};
    }

    byte[] data;
    int startIdx;
    if (len % 2 != 0) {
        data = new byte[(len / 2) + 1];
        data[0] = (byte) Character.digit(input.charAt(0), 16);
        startIdx = 1;
    } else {
        data = new byte[len / 2];
        startIdx = 0;
    }

    for (int i = startIdx; i < len; i += 2) {
        data[(i + 1) / 2] = (byte) ((Character.digit(input.charAt(i), 16) << 4)
                + Character.digit(input.charAt(i+1), 16));
    }
    return data;
}
Conor Svensson
quelle
2

Ich habe immer eine Methode wie verwendet

public static final byte[] fromHexString(final String s) {
    String[] v = s.split(" ");
    byte[] arr = new byte[v.length];
    int i = 0;
    for(String val: v) {
        arr[i++] =  Integer.decode("0x" + val).byteValue();

    }
    return arr;
}

Diese Methode teilt auf durch Leerzeichen getrennte Hex-Werte auf, aber es wäre nicht schwierig, die Zeichenfolge nach anderen Kriterien aufzuteilen, z. B. in Gruppierungen von zwei Zeichen.

pfranza
quelle
Die Verkettung der Zeichenfolgen ist nicht erforderlich. Verwenden Sie einfach Integer.valueOf (val, 16).
Michael Myers
Ich habe versucht, die Radix-Konvertierungen wie diese zu verwenden, und ich hatte gemischte Ergebnisse
pfranza
danke - seltsamerweise funktioniert es gut mit dieser Zeichenfolge: "9C001C" oder "001C21" und schlägt mit dieser fehl: "9C001C21" Ausnahme im Thread "main" java.lang.NumberFormatException: Für Eingabezeichenfolge: "9C001C21" bei java.lang. NumberFormatException.forInputString (Unbekannte Quelle)
Rafraf
(Das ist nicht seltsamer als im Byte/ byteFall: höchstes Bit ohne Führung gesetzt -)
Greybeard
2

Ich mag die Character.digit-Lösung, aber hier ist, wie ich sie gelöst habe

public byte[] hex2ByteArray( String hexString ) {
    String hexVal = "0123456789ABCDEF";
    byte[] out = new byte[hexString.length() / 2];

    int n = hexString.length();

    for( int i = 0; i < n; i += 2 ) {
        //make a bit representation in an int of the hex value 
        int hn = hexVal.indexOf( hexString.charAt( i ) );
        int ln = hexVal.indexOf( hexString.charAt( i + 1 ) );

        //now just shift the high order nibble and add them together
        out[i/2] = (byte)( ( hn << 4 ) | ln );
    }

    return out;
}
Kernel Panik
quelle
2

Der von Bert Regelink vorgelegte Kodex funktioniert einfach nicht. Versuche Folgendes:

import javax.xml.bind.DatatypeConverter;
import java.io.*;

public class Test
{  
    @Test
    public void testObjectStreams( ) throws IOException, ClassNotFoundException
    {     
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);

            String stringTest = "TEST";
            oos.writeObject( stringTest );

            oos.close();
            baos.close();

            byte[] bytes = baos.toByteArray();
            String hexString = DatatypeConverter.printHexBinary( bytes);
            byte[] reconvertedBytes = DatatypeConverter.parseHexBinary(hexString);

            assertArrayEquals( bytes, reconvertedBytes );

            ByteArrayInputStream bais = new ByteArrayInputStream(reconvertedBytes);
            ObjectInputStream ois = new ObjectInputStream(bais);

            String readString = (String) ois.readObject();

            assertEquals( stringTest, readString);
        }
    }
Sean Coffey
quelle
2
Dies ist wirklich ein anderes Problem und gehört wahrscheinlich zu einem anderen Thread.
Sean Coffey
1

Ich fand, dass Kernel Panic die für mich nützlichste Lösung hat, stieß jedoch auf Probleme, wenn die Hex-Zeichenfolge eine ungerade Zahl war. löste es so:

boolean isOdd(int value)
{
    return (value & 0x01) !=0;
}

private int hexToByte(byte[] out, int value)
{
    String hexVal = "0123456789ABCDEF"; 
    String hexValL = "0123456789abcdef";
    String st = Integer.toHexString(value);
    int len = st.length();
    if (isOdd(len))
        {
        len+=1; // need length to be an even number.
        st = ("0" + st);  // make it an even number of chars
        }
    out[0]=(byte)(len/2);
    for (int i =0;i<len;i+=2)
    {
        int hh = hexVal.indexOf(st.charAt(i));
            if (hh == -1)  hh = hexValL.indexOf(st.charAt(i));
        int lh = hexVal.indexOf(st.charAt(i+1));
            if (lh == -1)  lh = hexValL.indexOf(st.charAt(i+1));
        out[(i/2)+1] = (byte)((hh << 4)|lh);
    }
    return (len/2)+1;
}

Ich füge einem Array eine Anzahl von Hex-Zahlen hinzu, also übergebe ich den Verweis auf das Array, das ich verwende, und das Int, das ich konvertieren muss, und gebe die relative Position der nächsten Hex-Nummer zurück. Das letzte Byte-Array hat also [0] Anzahl von Hex-Paaren, [1 ...] Hex-Paare, dann die Anzahl von Paaren ...

Clayton Balabanov
quelle
1

Basierend auf der op-Voted-Lösung sollte Folgendes etwas effizienter sein:

  public static byte [] hexStringToByteArray (final String s) {
    if (s == null || (s.length () % 2) == 1)
      throw new IllegalArgumentException ();
    final char [] chars = s.toCharArray ();
    final int len = chars.length;
    final byte [] data = new byte [len / 2];
    for (int i = 0; i < len; i += 2) {
      data[i / 2] = (byte) ((Character.digit (chars[i], 16) << 4) + Character.digit (chars[i + 1], 16));
    }
    return data;
  }

Denn: Die anfängliche Konvertierung in ein char-Array erspart die Längenprüfungen in charAt

Philip Helger
quelle
1

Wenn Sie Java 8-Streams als Codierungsstil bevorzugen, können Sie dies nur mit JDK-Grundelementen erreichen.

String hex = "0001027f80fdfeff";

byte[] converted = IntStream.range(0, hex.length() / 2)
    .map(i -> Character.digit(hex.charAt(i * 2), 16) << 4 | Character.digit(hex.charAt((i * 2) + 1), 16))
    .collect(ByteArrayOutputStream::new,
             ByteArrayOutputStream::write,
             (s1, s2) -> s1.write(s2.toByteArray(), 0, s2.size()))
    .toByteArray();

Die , 0, s2.size()Parameter in der Collector-Verkettungsfunktion können weggelassen werden, wenn Sie nichts dagegen haben, zu fangen IOException.

Andy Brown
quelle
0
public static byte[] hex2ba(String sHex) throws Hex2baException {
    if (1==sHex.length()%2) {
        throw(new Hex2baException("Hex string need even number of chars"));
    }

    byte[] ba = new byte[sHex.length()/2];
    for (int i=0;i<sHex.length()/2;i++) {
        ba[i] = (Integer.decode(
                "0x"+sHex.substring(i*2, (i+1)*2))).byteValue();
    }
    return ba;
}
David V.
quelle
0

Meine formale Lösung:

/**
 * Decodes a hexadecimally encoded binary string.
 * <p>
 * Note that this function does <em>NOT</em> convert a hexadecimal number to a
 * binary number.
 *
 * @param hex Hexadecimal representation of data.
 * @return The byte[] representation of the given data.
 * @throws NumberFormatException If the hexadecimal input string is of odd
 * length or invalid hexadecimal string.
 */
public static byte[] hex2bin(String hex) throws NumberFormatException {
    if (hex.length() % 2 > 0) {
        throw new NumberFormatException("Hexadecimal input string must have an even length.");
    }
    byte[] r = new byte[hex.length() / 2];
    for (int i = hex.length(); i > 0;) {
        r[i / 2 - 1] = (byte) (digit(hex.charAt(--i)) | (digit(hex.charAt(--i)) << 4));
    }
    return r;
}

private static int digit(char ch) {
    int r = Character.digit(ch, 16);
    if (r < 0) {
        throw new NumberFormatException("Invalid hexadecimal string: " + ch);
    }
    return r;
}

Ist wie die PHP hex2bin () Funktion, aber im Java-Stil.

Beispiel:

String data = new String(hex2bin("6578616d706c65206865782064617461"));
// data value: "example hex data"
Daniel De León
quelle
0

Spät zur Party, aber ich habe die obige Antwort von DaveL zu einer Klasse mit umgekehrter Aktion zusammengefasst - nur für den Fall, dass es hilft.

public final class HexString {
    private static final char[] digits = "0123456789ABCDEF".toCharArray();

    private HexString() {}

    public static final String fromBytes(final byte[] bytes) {
        final StringBuilder buf = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            buf.append(HexString.digits[(bytes[i] >> 4) & 0x0f]);
            buf.append(HexString.digits[bytes[i] & 0x0f]);
        }
        return buf.toString();
    }

    public static final byte[] toByteArray(final String hexString) {
        if ((hexString.length() % 2) != 0) {
            throw new IllegalArgumentException("Input string must contain an even number of characters");
        }
        final int len = hexString.length();
        final byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        return data;
    }
}

Und JUnit-Testklasse:

public class TestHexString {

    @Test
    public void test() {
        String[] tests = {"0FA1056D73", "", "00", "0123456789ABCDEF", "FFFFFFFF"};

        for (int i = 0; i < tests.length; i++) {
            String in = tests[i];
            byte[] bytes = HexString.toByteArray(in);
            String out = HexString.fromBytes(bytes);
            System.out.println(in); //DEBUG
            System.out.println(out); //DEBUG
            Assert.assertEquals(in, out);

        }

    }

}
DrPhill
quelle
0

Ich weiß, dass dies ein sehr alter Thread ist, aber ich möchte immer noch meinen Penny hinzufügen.

Wenn ich wirklich eine einfache Hex-Zeichenfolge in einen Binärkonverter codieren muss, möchte ich dies wie folgt tun.

public static byte[] hexToBinary(String s){

  /*
   * skipped any input validation code
   */

  byte[] data = new byte[s.length()/2];

  for( int i=0, j=0; 
       i<s.length() && j<data.length; 
       i+=2, j++)
  {
     data[j] = (byte)Integer.parseInt(s.substring(i, i+2), 16);
  }

  return data;
}
Tigger
quelle
0

Bei weitem nicht die sauberste Lösung. Aber es funktioniert bei mir und ist gut formatiert:

private String createHexDump(byte[] msg, String description) {
    System.out.println();
    String result = "\n" + description;
    int currentIndex = 0;
    int printedIndex = 0;
    for(int i=0 ; i<msg.length ; i++){
        currentIndex++;
        if(i == 0){
            result += String.format("\n  %04x ", i);
        }
        if(i % 16 == 0 && i != 0){
            result += " | ";
            for(int j=(i-16) ; j<msg.length && j<i ; j++) {
                char characterToAdd = (char) msg[j];
                if (characterToAdd == '\n') {
                    characterToAdd = ' ';
                }
                result += characterToAdd;
                printedIndex++;
            }

            result += String.format("\n  %04x ", i);
        }

        result += String.format("%02x ", msg[i]);
    }

    if(currentIndex - printedIndex > 0){
        int leftOvers = currentIndex - printedIndex;
        for(int i=0 ; i<16-leftOvers ; i++){
            result += "   ";
        }

        result += " | ";

        for(int i=msg.length-leftOvers ; i<msg.length ; i++){
            char characterToAdd = (char) msg[i];
            if (characterToAdd == '\n') {
                characterToAdd = ' ';
            }
            result += characterToAdd;
        }
    }

    result += "\n";

    return result;
}

Die Ausgabe:

  S -> C
    0000 0b 00 2e 06 4d 6f 72 69 74 7a 53 6f 6d 65 20 54  |  .Heyyy Some T
    0010 43 50 20 73 74 75 66 66 20 49 20 63 61 70 74 75  | CP stuff I captu
    0020 72 65 64 2e 2e 77 65 6c 6c 20 66 6f 72 6d 61 74  | red..well format
    0030 3f                                               | ?
Moritz Schmidt
quelle
-2

Ich denke, ich werde es für dich tun. Ich habe es aus einer ähnlichen Funktion zusammengeschustert, die die Daten als Zeichenfolge zurückgegeben hat:

private static byte[] decode(String encoded) {
    byte result[] = new byte[encoded/2];
    char enc[] = encoded.toUpperCase().toCharArray();
    StringBuffer curr;
    for (int i = 0; i < enc.length; i += 2) {
        curr = new StringBuffer("");
        curr.append(String.valueOf(enc[i]));
        curr.append(String.valueOf(enc[i + 1]));
        result[i] = (byte) Integer.parseInt(curr.toString(), 16);
    }
    return result;
}
Bob King
quelle
Zunächst sollten Sie die Zeichenfolge nicht in Großbuchstaben konvertieren müssen. Zweitens ist es möglich, Zeichen direkt an einen StringBuffer anzuhängen, was wesentlich effizienter sein sollte.
Michael Myers
-2

Für mich war dies die Lösung, HEX = "FF01", dann aufgeteilt in FF (255) und 01 (01)

private static byte[] BytesEncode(String encoded) {
    //System.out.println(encoded.length());
    byte result[] = new byte[encoded.length() / 2];
    char enc[] = encoded.toUpperCase().toCharArray();
    String curr = "";
    for (int i = 0; i < encoded.length(); i=i+2) {
        curr = encoded.substring(i,i+2);
        System.out.println(curr);
        if(i==0){
            result[i]=((byte) Integer.parseInt(curr, 16));
        }else{
            result[i/2]=((byte) Integer.parseInt(curr, 16));
        }

    }
    return result;
}
Alejandro
quelle
Diese Frage wurde eine Weile beantwortet und es gibt mehrere gute Alternativen. Leider liefert Ihre Antwort zu diesem Zeitpunkt keinen wesentlich verbesserten Wert.
rfornal