Konvertieren Sie eine Zeichenfolgendarstellung eines Hex-Dumps mit Java in ein Byte-Array?
Lesezeit: 9 Minuten
rafraf
Ich suche nach einer Möglichkeit, eine lange Zeichenfolge (aus einem Dump) zu konvertieren, die Hex-Werte in ein Byte-Array darstellt.
Ich hätte es nicht besser formulieren können als die Person, die gepostet hat hier die gleiche Frage.
Aber um es originell zu halten, formuliere ich es auf meine eigene Weise: Angenommen, ich habe eine Zeichenfolge "00A0BF" das möchte ich so interpretieren
byte[] {0x00,0xA0,0xBf}
was soll ich machen?
Ich bin ein Java-Anfänger und habe es schließlich verwendet BigInteger und achten Sie auf führende Hex-Nullen. Aber ich finde es hässlich und ich bin sicher, dass ich etwas Einfaches vermisse.
Siehe auch stackoverflow.com/questions/9655181/….
– flow2k
23. Oktober 2018 um 18:54 Uhr
Ich habe gezähmt BigInteger Hier.
– John McClane
25. November 2018 um 1:34 Uhr
FWIW String.getBytes() wird nicht so funktionieren, wie du denkst. Musste das auf die harte Tour lernen. if ("FF".getBytes() != "ff".getBytes()) { System.out.println("Try again"); }
Hier ist eine Lösung, die meiner Meinung nach besser ist als alle bisher geposteten:
/* s must be an even-length string. */
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 für eine Verbesserung:
Sicher mit führenden Nullen (im Gegensatz zu BigInteger) und mit negativen Bytewerten (im Gegensatz zu Byte.parseByte)
Konvertiert den String nicht in a char[]oder erstellen Sie StringBuilder- und String-Objekte für jedes einzelne Byte.
Keine Bibliotheksabhängigkeiten, die möglicherweise nicht verfügbar sind
Fühlen Sie sich frei, die Argumentprüfung über hinzuzufügen assert oder Ausnahmen, wenn das Argument nicht als sicher bekannt ist.
Können Sie ein Beispiel geben, das falsch dekodiert wurde, oder erklären, warum es falsch ist?
– David L.
17. April 2011 um 14:35 Uhr
Es funktioniert nicht für den String “0”. Es löst eine java.lang.StringIndexOutOfBoundsException aus
– ovdsrn
8. Juni 2011 um 20:06 Uhr
“0” ist keine gültige Eingabe. Bytes erfordern jeweils zwei Hexadezimalziffern. In der Antwort heißt es: „Sie können gerne eine Argumentüberprüfung hinzufügen … wenn das Argument nicht als sicher bekannt ist.“
– David L.
9. Juni 2011 um 16:42 Uhr
javax.xml.bind.DatatypeConverter.parseHexBinary(hexString) scheint in meinen Mikrotests etwa 20% schneller zu sein als die obige Lösung (für was auch immer sie wert sind) und löst korrekt Ausnahmen bei ungültigen Eingaben aus (z. B. “gg” ist kein gültiger hexString, gibt aber -77 zurück, wenn die vorgeschlagene Lösung verwendet wird).
– Trevor Freemann
4. April 2012 um 18:31 Uhr
@DaedalusAlpha Es hängt von Ihrem Kontext ab, aber normalerweise finde ich es besser, mit solchen Dingen schnell und laut zu scheitern, damit Sie Ihre Annahmen korrigieren können, anstatt stillschweigend falsche Daten zurückzugeben.
– David L.
17. Juni 2015 um 16:03 Uhr
Wladislav Rastrusny
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 es zu einer ClassNotFoundException führt, es sei denn, Sie geben –add-modules java.se.ee an (danke an @eckes)
Nicht verfügbar für Android (danke an Fabian für die Notiz), aber Sie können einfach den Quellcode nehmen, wenn Ihr System fehlt javax.xml aus irgendeinem Grund. Dank an @Bert Regelink um die Quelle zu extrahieren.
IMHO sollte dies die akzeptierte / beste Antwort sein, da es kurz ist und reinigen (im Gegensatz zur Antwort von @ DaveL) und erfordert keine externen Bibliotheken (wie die Antwort von skaffman). Ebenfalls, .
– Priidu Neemre
18. August 2015 um 12:40 Uhr
die datatypeconverter-Klasse ist beispielsweise in Android nicht verfügbar.
– Fabian
10. Februar 2016 um 12:41 Uhr
Warnung: in Java 9 Jigsaw ist dies nicht mehr Teil des (Standard) java.se Wurzelsatz, so dass es zu a führt ClassNotFoundException es sei denn, Sie geben an --add-modules java.se.ee
– eckes
10. November 2016 um 12:17 Uhr
@dantebarba denke ich javax.xml.bind.DatatypeConverter bietet bereits eine Methode zum Codieren/Decodieren von Base64-Daten. Sehen parseBase64Binary() und printBase64Binary().
– DragShot
3. Juli 2017 um 22:18 Uhr
Um die Probleme mit zu ergänzen DataTypeConverter, Java SE 11 hat die JAXB-API vollständig entfernt und ist jetzt nur noch in Java EE enthalten. Sie können es auch als Maven-Abhängigkeit hinzufügen, wie hier vorgeschlagen: stackoverflow.com/a/43574427/7347751
– David Mordigal
30. Januar 2019 um 5:51 Uhr
Skaffmann
Die Hex-Klasse im Commons-Codec sollte das für Sie erledigen.
Das sieht auch gut aus. Siehe org.apache.commons.codec.binary.Hex.decodeHex()
– David L.
26. September 2008 um 17:46 Uhr
Es war interessant. Aber ich fand ihre Lösung schwer nachzuvollziehen. Hat es Vorteile gegenüber dem, was Sie vorgeschlagen haben (außer der Überprüfung auf eine gerade Anzahl von Zeichen)?
– raffaf
27. September 2008 um 1:06 Uhr
Jontro
Sie können jetzt verwenden BaseEncoding in guava um das zu erreichen.
BaseEncoding.base16().decode(string);
Um es umzukehren, verwenden Sie
BaseEncoding.base16().encode(bytes);
David L.
Eigentlich finde ich die BigInteger-Lösung sehr schön:
new BigInteger("00A0BF", 16).toByteArray();
Bearbeiten: Nicht sicher für führende Nullenwie auf dem Plakat vermerkt.
Dachte ich anfangs auch. Und danke, dass Sie es dokumentiert haben – ich dachte nur, ich sollte es tun … es hat einige seltsame Dinge getan, die ich nicht wirklich verstanden habe – wie einige führende 0x00 wegzulassen und auch die Reihenfolge von 1 Byte in einer 156-Byte-Zeichenfolge zu verwechseln I spielte mit.
– raffaf
26. September 2008 um 16:43 Uhr
Das ist ein guter Punkt über führende Nullen. Ich bin mir nicht sicher, ob ich glaube, dass es die Reihenfolge der Bytes verwechseln könnte, und wäre sehr daran interessiert, es demonstriert zu sehen.
– David L.
26. September 2008 um 16:55 Uhr
Ja, sobald ich es gesagt habe, habe ich es mir auch nicht geglaubt 🙂 Ich habe einen Vergleich des Byte-Arrays von BigInteger mit mmyers’fromHexString und (ohne 0x00) mit dem anstößigen String durchgeführt – sie waren identisch. Die “Verwechslung” ist passiert, aber es kann etwas anderes gewesen sein. Ich werde morgen genauer hinschauen
– raffaf
26. September 2008 um 17:09 Uhr
Das Problem mit BigInteger ist, dass es ein “Vorzeichenbit” geben muss. Wenn das führende Byte das High-Bit gesetzt hat, hat das resultierende Byte-Array eine zusätzliche 0 an der 1. Position. Aber immer noch +1.
– Grau
28. Oktober 2011 um 16:20 Uhr
Gemeinschaft
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 dahinter interessieren Einzeiler von FractalizeR (ich brauchte das, da javax.xml.bind nicht für Android verfügbar ist (standardmäßig)), das kommt 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();
}
Dachte ich anfangs auch. Und danke, dass Sie es dokumentiert haben – ich dachte nur, ich sollte es tun … es hat einige seltsame Dinge getan, die ich nicht wirklich verstanden habe – wie einige führende 0x00 wegzulassen und auch die Reihenfolge von 1 Byte in einer 156-Byte-Zeichenfolge zu verwechseln I spielte mit.
– raffaf
26. September 2008 um 16:43 Uhr
Das ist ein guter Punkt über führende Nullen. Ich bin mir nicht sicher, ob ich glaube, dass es die Reihenfolge der Bytes verwechseln könnte, und wäre sehr daran interessiert, es demonstriert zu sehen.
– David L.
26. September 2008 um 16:55 Uhr
Ja, sobald ich es gesagt habe, habe ich es mir auch nicht geglaubt 🙂 Ich habe einen Vergleich des Byte-Arrays von BigInteger mit mmyers’fromHexString und (ohne 0x00) mit dem anstößigen String durchgeführt – sie waren identisch. Die “Verwechslung” ist passiert, aber es kann etwas anderes gewesen sein. Ich werde morgen genauer hinschauen
– raffaf
26. September 2008 um 17:09 Uhr
Das Problem mit BigInteger ist, dass es ein “Vorzeichenbit” geben muss. Wenn das führende Byte das High-Bit gesetzt hat, hat das resultierende Byte-Array eine zusätzliche 0 an der 1. Position. Aber immer noch +1.
– Grau
28. Oktober 2011 um 16:20 Uhr
Anil Bharadia
Die HexBinaryAdapter bietet die Möglichkeit zum Marshallen und Unmarshall zwischen String und 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 eigentlich nur so, wie es ist, und muss keine separate Methode für die Verwendung erstellen.
Es funktioniert nur, wenn die Eingabezeichenfolge (hexString) eine gerade Anzahl von Zeichen hat. Sonst: Ausnahme im Thread “main” java.lang.IllegalArgumentException: hexBinary muss gerade Länge haben:
– ovdsrn
8. Juni 2011 um 20:15 Uhr
Oh, danke für den Hinweis. Ein Benutzer sollte wirklich keine ungerade Anzahl von Zeichen haben, da das Byte-Array als {0x00,0xA0,0xBf} dargestellt wird. Jedes Byte hat zwei Hexadezimalziffern oder Halbbytes. Eine beliebige Anzahl von Bytes sollte also immer eine gerade Anzahl von Zeichen haben. Danke, dass du das erwähnt hast.
– GrkIngenieur
16. Juni 2011 um 15:54 Uhr
Sie können java.xml.bind.DatatypeConverter.parseHexBinary(hexString) direkt verwenden, anstatt HexBinaryAdapter zu verwenden (der wiederum DatatypeConverter aufruft). Auf diese Weise müssen Sie kein Adapterinstanzobjekt erstellen (da DatatypeConverter-Methoden statisch sind).
– Trevor Freemann
4. April 2012 um 18:33 Uhr
javax.xml.bind.* ist in Java 9 nicht mehr verfügbar. Das Gefährliche ist, dass Code, der es verwendet, unter Java 1.8 oder früher (Java 9 mit Quelleinstellungen früher) kompiliert wird, aber eine Laufzeitausnahme erhält, die unter Java 9 ausgeführt wird.
– Stephen M -im Streik-
28. August 2017 um 16:52 Uhr
9756400cookie-checkKonvertieren Sie eine Zeichenfolgendarstellung eines Hex-Dumps mit Java in ein Byte-Array?yes
Siehe auch stackoverflow.com/questions/9655181/….
– flow2k
23. Oktober 2018 um 18:54 Uhr
Ich habe gezähmt
BigInteger
Hier.– John McClane
25. November 2018 um 1:34 Uhr
FWIW
String.getBytes()
wird nicht so funktionieren, wie du denkst. Musste das auf die harte Tour lernen.if ("FF".getBytes() != "ff".getBytes()) { System.out.println("Try again"); }
– tir38
11. September 2019 um 17:05 Uhr