Wie konvertiere ich ein Byte-Array in eine Hex-Zeichenfolge in Java?
649
Ich habe ein Byte-Array, das mit Hex-Zahlen gefüllt ist, und das einfache Drucken ist ziemlich sinnlos, da es viele nicht druckbare Elemente gibt. Was ich brauche, ist der genaue Hexcode in Form von:3a5f771c
Probieren Sie es einfach zuerst aus und zeigen Sie uns, was Sie haben. Sie haben nichts zu verlieren und alles zu gewinnen. Integer hat eine toHexString(...)Methode, die helfen kann, wenn Sie danach suchen. Auch String.format(...)können einige nette Formatierung Tricks tun , um die Verwendung von %2xCode - String.
"Was ich brauche, ist der genaue Hexcode in Form von: 3a5f771c ..." - Sie haben nach einem genauen Formular gefragt, aber kein genaues Beispiel angegeben. Konvertieren Sie die ersten vier Bytes in eine Zeichenfolge und verketten Sie dann die Ellipsen mit der Zeichenfolge.
Jww
1
Mit Hilfe von Stream in Java 8 kann es einfach implementiert werden als: static String byteArrayToHex (byte [] a) {return IntStream.range (0, a.length) .mapToObj (i -> String.format ("% 02x") ", a [i])) .reduce ((acc, v) -> acc +" "+ v) .get (); }
Tibetty
Antworten:
900
Aus der Diskussion hier und insbesondere aus dieser Antwort geht hervor, dass dies die Funktion ist, die ich derzeit verwende:
Meine eigenen kleinen Benchmarks (eine Million Bytes tausendmal, 256 Bytes zehn Millionen Mal) zeigten, dass es viel schneller ist als jede andere Alternative, ungefähr die Hälfte der Zeit auf langen Arrays. Im Vergleich zu der Antwort, aus der ich sie übernommen habe, konnte durch das Umschalten auf bitweise Operationen - wie in der Diskussion vorgeschlagen - die Zeit für lange Arrays um etwa 20% verkürzt werden. (Bearbeiten: Wenn ich sage, dass es schneller als die Alternativen ist, meine ich den in den Diskussionen angebotenen alternativen Code. Die Leistung entspricht dem Commons Codec, der sehr ähnlichen Code verwendet.)
2k20-Version in Bezug auf Java 9-Kompaktzeichenfolgen:
Ich habe gerade javax.xml.bind.DataTypeConverter gefunden , einen Teil der Standarddistribution. Warum taucht das nicht auf, wenn Sie diese Art von Problem googeln? Viele hilfreiche Tools, einschließlich String printHexBinary(byte[])und byte[] parseHexBinary(String). printHexBinaryist jedoch viel (2x) langsamer als die Funktion in dieser Antwort. (Ich habe die Quelle überprüft; sie verwendet ein stringBuilder. parseHexBinaryVerwendet ein Array.) Wirklich, für die meisten Zwecke ist es jedoch schnell genug und Sie haben es wahrscheinlich bereits.
VielleichtWeCouldStealAVan
75
+1 für die Antwort, da Android keinen DataTypeConverter hat
Vaiden
7
@maybeWeCouldStealAVan: JDK 7 ist jetzt Open Source. Wir sollten einen Patch einreichen, um die Leistung für zu verbessern printHexBinary.
Kevinarpe
3
@maybeWeCouldStealAVan Könnten Sie bitte erklären, wie dies funktioniert. Ich folge größtenteils, mag es aber wirklich zu verstehen, was bei der Verwendung von Code passiert. Vielen Dank!
JJNford
24
javax.xml.bind.DataTypeConverterwird aus Java 11 entfernt.
The Impaler
420
Die Apache Commons Codec- Bibliothek verfügt über eine Hex- Klasse, die genau diese Art von Arbeit erledigt.
import org.apache.commons.codec.binary.Hex;String foo ="I am a string";byte[] bytes = foo.getBytes();System.out.println(Hex.encodeHexString( bytes ));
@cytinus - Meine Ablehnung erfolgte vor 4 Monaten, daher bin ich mir nicht ganz sicher, was ich dachte, aber ich habe wahrscheinlich Einwände gegen die Größe der Bibliothek erhoben. Dies ist eine kleine Funktion innerhalb des Programms. Es ist nicht erforderlich, dem Projekt eine so umfangreiche Bibliothek hinzuzufügen, um es auszuführen.
ArtOfWarfare
6
@ArtOfWarefare Ich stimme zu, also anstatt import org.apache.commons.codec.*;Sie könntenimport org.apache.commons.codec.binary.Hex;
Cytinus
12
@ArtOfWarfare Ich muss nicht zustimmen. Das einzig Schreckliche ist, dass die Apache-Commons-Bibliotheken standardmäßig nicht in JRE und JDK enthalten sind. Es gibt einige Bibliotheken, die so nützlich sind, dass sie sich standardmäßig auf Ihrem Klassenpfad befinden sollten, und dies ist eine davon.
CorsiKa
28
Ich empfehle dringend, diese Antwort als Top-Antwort auszutauschen. Stimmen Sie immer ab, um eine gut getestete, performante Open-Source-Bibliothek über benutzerdefiniertem Code zu verwenden, der sich nicht verbessert.
Dmitriy Likhten
6
Oder wenn Sie BouncyCastle ( org.bouncycastle: bcprov-jdk15on ) verwenden, können Sie diese Klasse verwenden: org.bouncycastle.util.encoders.Hexmit dieser Methode:String toHexString(byte[] data)
In Java 8 und früheren Versionen war JAXB Teil der Java-Standardbibliothek. Es wurde als veraltet mit Java 9 und entfernt mit Java 11 , als Teil der Bemühungen , alle Java EE - Pakete in ihre eigenen Bibliotheken zu bewegen. Es ist eine lange Geschichte . Jetzt javax.xml.bindnicht vorhanden, und wenn Sie JAXB verwenden möchten, das enthält DatatypeConverter, müssen Sie die JAXB-API und JAXB Runtime von Maven installieren .
Eine gute Lösung, die leider nicht für Android gültig ist.
Kazriko
@Kazriko Vielleicht möchten Sie code.google.com/p/dalvik/wiki/JavaxPackages lesen . Es ist eine Möglichkeit, Javax-Klassen in Android zu integrieren. Aber wenn Sie nur in Hex konvertieren möchten, ist es die Mühe nicht wert.
PhoneixS
13
DatatypeConverter ist ab JDK 9
pmcollins
3
@PhoneixS Es ist immer noch vorhanden, aber nicht Teil der Standardlaufzeit (aufgrund von Java 9-Modulen).
Spotlight
2
Verlassen Sie sich nicht auf javax.xml.bind, es wird gut kompiliert, kann aber zur Laufzeit nicht gefunden werden. Wenn Sie dies tun, seien Sie bereit, mit java.lang.NoClassDefFoundError
Dmitry
227
Einfachste Lösung, keine externen Bibliotheken, keine Ziffernkonstanten:
Dies ist sehr langsam, im Durchschnitt 1000-mal langsamer (für 162 Bytes lang) als in der oberen Antwort. Vermeiden Sie die Verwendung von String.Format, wenn die Leistung wichtig ist.
Pt123
8
Vielleicht langsam. Es ist gut für Dinge, die gelegentlich passieren, wie zum Beispiel Login oder ähnliches.
Zeiger Null
29
Wenn es langsam ist, was dann? In meinem Anwendungsfall handelt es sich nur um eine Debug-Anweisung. Vielen Dank für dieses Codefragment.
Wikingersteve
8
Die Wiederverwendung einer Bibliothek durch Hinzufügen zusätzlicher JAR-Dateien mit mehreren Dutzend kB wäre nicht gerade effizient, wenn Sie nur diese Funktion benötigen (auf einigen Plattformen wie Android wird das gesamte Jar in die Endanwendung aufgenommen). Und manchmal ist kürzerer und klarerer Code besser, wenn keine Leistung benötigt wird.
personne3000
2
@ personne3000 vielleicht, aber in diesem Fall benötigen Sie Stream-Unterstützung, keine einzige Anruffunktion. Dieser ist leicht zu verstehen und zu merken und daher zu pflegen.
In Guave können Sie auch verwenden new HashCode(bytes).toString().
mfulton26
1
Ab Guava 22.0 ist esHashCode.fromBytes(checksum).toString()
Devstr
41
Dieser einfache Oneliner funktioniert für mich BEARBEITEN String result = new BigInteger(1, inputBytes).toString(16);
- Wenn Sie diesen verwenden, werden die führenden Nullen entfernt, aber sie haben für meinen Anwendungsfall funktioniert. Vielen Dank an @Voicu für den Hinweis
@Voicu ... Und es wird in 50% der Fälle eine führende Null hinzufügen.
Maarten Bodewes
26
Hier sind einige gängige Optionen, die von einfach (einzeilig) bis komplex (riesige Bibliothek) geordnet sind. Wenn Sie an Leistung interessiert sind, lesen Sie die folgenden Mikro-Benchmarks.
Option 1: Code-Snippet - Einfach
Eine sehr einfache Lösung ist die Verwendung der BigIntegerHex-Darstellung:
newBigInteger(1, someByteArray).toString(16)
Da dies Zahlen behandelt, die keine willkürlichen Byte-Strings sind , werden führende Nullen weggelassen - dies kann das sein, was Sie wollen oder nicht (z. B. 000AE3vs 0AE3für eine 3-Byte-Eingabe). Dies ist auch sehr langsam, etwa 100x langsamer als bei der nächsten Option.
Option 2: Code-Snippet - Erweitert
Hier ist ein voll ausgestattetes, kopierfähiges und einfügbares Code-Snippet, das Groß- / Kleinbuchstaben und Endianness unterstützt . Es ist optimiert, um die Speicherkomplexität zu minimieren und die Leistung zu maximieren, und sollte mit allen modernen Java-Versionen (5+) kompatibel sein.
privatestaticfinalchar[] LOOKUP_TABLE_LOWER =newchar[]{0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x61,0x62,0x63,0x64,0x65,0x66};privatestaticfinalchar[] LOOKUP_TABLE_UPPER =newchar[]{0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46};publicstaticString encode(byte[] byteArray,boolean upperCase,ByteOrder byteOrder){// our output size will be exactly 2x byte-array lengthfinalchar[] buffer =newchar[byteArray.length *2];// choose lower or uppercase lookup tablefinalchar[] lookup = upperCase ? LOOKUP_TABLE_UPPER : LOOKUP_TABLE_LOWER;int index;for(int i =0; i < byteArray.length; i++){// for little endian we count from last to first
index =(byteOrder ==ByteOrder.BIG_ENDIAN)? i : byteArray.length - i -1;// extract the upper 4 bit and look up char (0-A)
buffer[i <<1]= lookup[(byteArray[index]>>4)&0xF];// extract the lower 4 bit and look up char (0-A)
buffer[(i <<1)+1]= lookup[(byteArray[index]&0xF)];}returnnewString(buffer);}publicstaticString encode(byte[] byteArray){return encode(byteArray,false,ByteOrder.BIG_ENDIAN);}
Den vollständigen Quellcode mit Apache v2 Lizenz und Decoder finden Sie hier .
Option 3: Verwenden einer kleinen optimierten Bibliothek: bytes-java
Während ich an meinem vorherigen Projekt gearbeitet habe, habe ich dieses kleine Toolkit für die Arbeit mit Bytes in Java erstellt. Es hat keine externen Abhängigkeiten und ist mit Java 7+ kompatibel. Es enthält unter anderem einen sehr schnellen und gut getesteten HEX en / decoder:
Natürlich gibt es die guten alten Codecs . ( warnende Meinung voraus ) Während ich an dem oben beschriebenen Projekt arbeitete, analysierte ich den Code und war ziemlich enttäuscht. Viele doppelte unorganisierte Codes, veraltete und exotische Codecs sind wahrscheinlich nur für sehr wenige und ziemlich überentwickelte und langsame Implementierungen beliebter Codecs (insbesondere Base64) nützlich. Ich würde daher eine fundierte Entscheidung treffen, wenn Sie es oder eine Alternative verwenden möchten. Wenn Sie es dennoch verwenden möchten, finden Sie hier einen Code-Ausschnitt:
Nicht wirklich Option 8: Java 9+ -Kompatibilität oder 'JAXBs nicht verwenden javax / xml / bind / DatatypeConverter'
In früheren Java-Versionen (8 und niedriger) war der Java-Code für JAXB als Laufzeitabhängigkeit enthalten. Seit Java 9 und Jigsaw Modularisierung Ihr Code ohne explizite Deklaration nicht auf anderen Code außerhalb seines Moduls zugreifen. Seien Sie sich also bewusst, wenn Sie eine Ausnahme erhalten wie:
beim Ausführen auf einer JVM mit Java 9+. Wenn ja, wechseln Sie die Implementierung zu einer der oben genannten Alternativen. Siehe auch dies Frage .
Mikro-Benchmarks
Hier sind die Ergebnisse eines einfachen JMH- Mikro-Benchmarks, der Byte-Arrays unterschiedlicher Größe codiert . Die Werte sind Operationen pro Sekunde, also ist höher besser.
Beachten Sie, dass Mikro-Benchmarks sehr oft kein reales Verhalten darstellen. Nehmen Sie diese Ergebnisse daher mit einem Körnchen Salz.
|Name(ops/s)|16byte|32byte|128byte|0.95 MB ||----------------------|-----------:|-----------:|----------:|--------:||Opt1:BigInteger|2,088,514|1,008,357|133,665|4||Opt2/3:BytesLib|20,423,170|16,049,841|6,685,522|825||Opt4:ApacheCommons|17,503,857|12,382,018|4,319,898|529||Opt5:Guava|10,177,925|6,937,833|2,094,658|257||Opt6:Spring|18,704,986|13,643,374|4,904,805|601||Opt7: BC |7,501,666|3,674,422|1,077,236|152||Opt8: JAX-B |13,497,736|8,312,834|2,590,940|346|
Technische Daten: JDK 8u202, i7-7700K, Win10, 24 GB RAM. Den vollständigen Benchmark finden Sie hier .
Das eleganteste, wie er auch bemerkt, denke ich, ist dieses:
staticfinalString HEXES ="0123456789ABCDEF";publicstaticString getHex(byte[] raw ){if( raw ==null){returnnull;}finalStringBuilder hex =newStringBuilder(2* raw.length );for(finalbyte b : raw ){
hex.append(HEXES.charAt((b &0xF0)>>4)).append(HEXES.charAt((b &0x0F)));}return hex.toString();}
Andere Methoden liefen auf meinem 64-Byte-Beispiel in 5 ms, dieses läuft in 0 ms. Wahrscheinlich am besten, da keine anderen String-Funktionen wie das Format vorhanden sind.
Joseph Lust
if (raw == null) return nullist nicht schnell ausfallen. Warum würden Sie jemals einen nullSchlüssel verwenden?
Maarten Bodewes
Ich nehme an, es ist eine Gewohnheit, Validierung einzugeben. In diesem Fall verhindern wir jede Nullreferenzausnahme und überlassen es dem Aufrufer, fehlerhafte Daten zu verarbeiten.
Michael Bisbjerg
16
Bei den geringen Kosten für das Speichern der Nachschlagetabelle ist diese Implementierung einfach und sehr schnell.
Warum nicht das BYTE2HEXArray mit einem einfachen forZyklus initialisieren ?
icza
@icza Ist das überhaupt mit einem statischen Endfeld (auch bekannt als Konstante) möglich?
Nevelis
1
@nevelis Es kann in einem static { }Block zugewiesen werden .
よ ル ち ゃ ん だ よ
1
@icza, weil es schneller ist, eine Nachschlagetabelle fest zu codieren, als sie zu generieren. Hier wird die Speicherkomplexität mit der Zeitkomplexität gehandelt, d. H. braucht mehr Speicher, aber schneller (jeweils ein wenig an beiden Enden)
Patrick Favre
8
Wie wäre es damit?
String byteToHex(finalbyte[] hash){Formatter formatter =newFormatter();for(byte b : hash){
formatter.format("%02x", b);}String result = formatter.toString();
formatter.close();return result;}
Es ist eine etwas flexiblere Anpassung der akzeptierten Antwort. Persönlich behalte ich sowohl die akzeptierte Antwort als auch diese Überlastung bei, die in mehr Kontexten verwendet werden kann.
Wenn Ihr Debuffer einen schlechten Tag hat, versuchen Sie, die StringBuilder-Instanziierung mit einer Reihe von Zeichen zu unterstützen, um Folgendes zu unterstützen : StringBuilder buf = new StringBuilder(data.length * 2);.
Graubart
2
Ok, es gibt eine Reihe von Möglichkeiten, dies zu tun. Wenn Sie sich jedoch für die Verwendung einer Bibliothek entscheiden, würde ich empfehlen, in Ihrem Projekt nachzuschauen, ob in einer Bibliothek, die bereits Teil Ihres Projekts ist, etwas implementiert wurde, bevor Sie eine neue Bibliothek hinzufügen nur um das zu tun. Zum Beispiel, wenn Sie noch nicht haben
Das Hinzufügen eines Utility-JAR für einfache Funktionen ist keine gute Option. Stellen Sie stattdessen Ihre eigenen Dienstprogrammklassen zusammen. Folgendes ist eine schnellere Implementierung möglich.
Eine kleine Variante der von @maybewecouldstealavan vorgeschlagenen Lösung, mit der Sie N Bytes in der Ausgabe-Hex-Zeichenfolge visuell bündeln können:
Auf dieser Seite kann keine Lösung gefunden werden, die dies nicht tut
Verwenden Sie eine Schleife
Verwenden Sie javax.xml.bind.DatatypeConverter, das gut kompiliert, aber zur Laufzeit häufig java.lang.NoClassDefFoundError auslöst.
Hier ist eine Lösung, die die oben genannten Mängel nicht aufweist (keine Versprechen, meine hat jedoch keine anderen Mängel)
import java.math.BigInteger;importstatic java.lang.System.out;publicfinalclassApp2{// | proposed solution.publicstaticString encode(byte[] bytes){finalint length = bytes.length;// | BigInteger constructor throws if it is given an empty array.if(length ==0){return"00";}finalint evenLength =(int)(2*Math.ceil(length /2.0));finalString format ="%0"+ evenLength +"x";finalString result =String.format (format,newBigInteger(bytes));return result;}publicstaticvoid main(String[] args)throwsException{// 00
out.println(encode(newbyte[]{}));// 01
out.println(encode(newbyte[]{1}));//203040
out.println(encode(newbyte[]{0x20,0x30,0x40}));// 416c6c20796f75722062617365206172652062656c6f6e6720746f2075732e
out.println(encode("All your base are belong to us.".getBytes()));}}
Ich konnte dies nicht unter 62 Opcodes bekommen, aber wenn Sie ohne 0-Auffüllung leben können, falls das erste Byte kleiner als 0x10 ist, dann verwendet die folgende Lösung nur 23 Opcodes. Zeigt wirklich, wie "einfach, sich selbst zu implementieren" -Lösungen wie "Pad mit einer Null, wenn die Zeichenfolgenlänge ungerade ist" ziemlich teuer werden können, wenn eine native Implementierung noch nicht verfügbar ist (oder in diesem Fall, wenn BigInteger die Option hatte, Nullen vorangestellt zu haben toString).
publicstaticString encode(byte[] bytes){finalint length = bytes.length;// | BigInteger constructor throws if it is given an empty array.if(length ==0){return"00";}returnnewBigInteger(bytes).toString(16);}
Meine Lösung basiert auf der Lösung von MaybeWeCouldStealAVan, basiert jedoch nicht auf zusätzlich zugewiesenen Nachschlagetabellen. Es werden keine "int-to-char" -Cast-Hacks verwendet (tatsächlich wird Character.forDigit()ein Vergleich durchgeführt, um zu überprüfen, was die Ziffer wirklich ist) und daher möglicherweise etwas langsamer. Bitte benutzen Sie es, wo immer Sie wollen. Prost.
publicstaticString bytesToHex(finalbyte[] bytes){finalint numBytes = bytes.length;finalchar[] container =newchar[numBytes *2];for(int i =0; i < numBytes; i++){finalint b = bytes[i]&0xFF;
container[i *2]=Character.forDigit(b >>>4,0x10);
container[i *2+1]=Character.forDigit(b &0xF,0x10);}returnnewString(container);}
publicstaticbyte[] hexStringToByteArray(String s){int len = s.length();byte[] data =newbyte[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;}
privatestaticString bytesToHexString(byte[] bytes,int length){if(bytes ==null|| length ==0)returnnull;StringBuilder ret =newStringBuilder(2*length);for(int i =0; i < length ; i++){int b;
b =0x0f&(bytes[i]>>4);
ret.append("0123456789abcdef".charAt(b));
b =0x0f& bytes[i];
ret.append("0123456789abcdef".charAt(b));}return ret.toString();}
toHexString(...)
Methode, die helfen kann, wenn Sie danach suchen. AuchString.format(...)
können einige nette Formatierung Tricks tun , um die Verwendung von%2x
Code - String.Antworten:
Aus der Diskussion hier und insbesondere aus dieser Antwort geht hervor, dass dies die Funktion ist, die ich derzeit verwende:
Meine eigenen kleinen Benchmarks (eine Million Bytes tausendmal, 256 Bytes zehn Millionen Mal) zeigten, dass es viel schneller ist als jede andere Alternative, ungefähr die Hälfte der Zeit auf langen Arrays. Im Vergleich zu der Antwort, aus der ich sie übernommen habe, konnte durch das Umschalten auf bitweise Operationen - wie in der Diskussion vorgeschlagen - die Zeit für lange Arrays um etwa 20% verkürzt werden. (Bearbeiten: Wenn ich sage, dass es schneller als die Alternativen ist, meine ich den in den Diskussionen angebotenen alternativen Code. Die Leistung entspricht dem Commons Codec, der sehr ähnlichen Code verwendet.)
2k20-Version in Bezug auf Java 9-Kompaktzeichenfolgen:
quelle
String printHexBinary(byte[])
undbyte[] parseHexBinary(String)
.printHexBinary
ist jedoch viel (2x) langsamer als die Funktion in dieser Antwort. (Ich habe die Quelle überprüft; sie verwendet einstringBuilder
.parseHexBinary
Verwendet ein Array.) Wirklich, für die meisten Zwecke ist es jedoch schnell genug und Sie haben es wahrscheinlich bereits.printHexBinary
.javax.xml.bind.DataTypeConverter
wird aus Java 11 entfernt.Die Apache Commons Codec- Bibliothek verfügt über eine Hex- Klasse, die genau diese Art von Arbeit erledigt.
quelle
import org.apache.commons.codec.*;
Sie könntenimport org.apache.commons.codec.binary.Hex;
org.bouncycastle.util.encoders.Hex
mit dieser Methode:String toHexString(byte[] data)
Die Methode
javax.xml.bind.DatatypeConverter.printHexBinary()
, die Teil der Java-Architektur für XML-Bindung (JAXB) ist , war eine bequeme Möglichkeit, einebyte[]
in eine Hex-Zeichenfolge zu konvertieren . DieDatatypeConverter
Klasse enthielt auch viele andere nützliche Datenmanipulationsmethoden.In Java 8 und früheren Versionen war JAXB Teil der Java-Standardbibliothek. Es wurde als veraltet mit Java 9 und entfernt mit Java 11 , als Teil der Bemühungen , alle Java EE - Pakete in ihre eigenen Bibliotheken zu bewegen. Es ist eine lange Geschichte . Jetzt
javax.xml.bind
nicht vorhanden, und wenn Sie JAXB verwenden möchten, das enthältDatatypeConverter
, müssen Sie die JAXB-API und JAXB Runtime von Maven installieren .Anwendungsbeispiel:
Wird darin enden, dass:
Diese Antwort ist dieselbe wie diese .
quelle
Einfachste Lösung, keine externen Bibliotheken, keine Ziffernkonstanten:
quelle
Eine Guavenlösung der Vollständigkeit halber:
Jetzt
hex
ist"48656c6c6f20776f726c64"
.quelle
new HashCode(bytes).toString()
.HashCode.fromBytes(checksum).toString()
Dieser einfache Oneliner funktioniert für mich BEARBEITEN
String result = new BigInteger(1, inputBytes).toString(16);
- Wenn Sie diesen verwenden, werden die führenden Nullen entfernt, aber sie haben für meinen Anwendungsfall funktioniert. Vielen Dank an @Voicu für den Hinweis
quelle
Hier sind einige gängige Optionen, die von einfach (einzeilig) bis komplex (riesige Bibliothek) geordnet sind. Wenn Sie an Leistung interessiert sind, lesen Sie die folgenden Mikro-Benchmarks.
Option 1: Code-Snippet - Einfach
Eine sehr einfache Lösung ist die Verwendung der
BigInteger
Hex-Darstellung:Da dies Zahlen behandelt, die keine willkürlichen Byte-Strings sind , werden führende Nullen weggelassen - dies kann das sein, was Sie wollen oder nicht (z. B.
000AE3
vs0AE3
für eine 3-Byte-Eingabe). Dies ist auch sehr langsam, etwa 100x langsamer als bei der nächsten Option.Option 2: Code-Snippet - Erweitert
Hier ist ein voll ausgestattetes, kopierfähiges und einfügbares Code-Snippet, das Groß- / Kleinbuchstaben und Endianness unterstützt . Es ist optimiert, um die Speicherkomplexität zu minimieren und die Leistung zu maximieren, und sollte mit allen modernen Java-Versionen (5+) kompatibel sein.
Den vollständigen Quellcode mit Apache v2 Lizenz und Decoder finden Sie hier .
Option 3: Verwenden einer kleinen optimierten Bibliothek: bytes-java
Während ich an meinem vorherigen Projekt gearbeitet habe, habe ich dieses kleine Toolkit für die Arbeit mit Bytes in Java erstellt. Es hat keine externen Abhängigkeiten und ist mit Java 7+ kompatibel. Es enthält unter anderem einen sehr schnellen und gut getesteten HEX en / decoder:
Sie können es auf Github auschecken: bytes-java .
Option 4: Apache Commons Codec
Natürlich gibt es die guten alten Codecs . ( warnende Meinung voraus ) Während ich an dem oben beschriebenen Projekt arbeitete, analysierte ich den Code und war ziemlich enttäuscht. Viele doppelte unorganisierte Codes, veraltete und exotische Codecs sind wahrscheinlich nur für sehr wenige und ziemlich überentwickelte und langsame Implementierungen beliebter Codecs (insbesondere Base64) nützlich. Ich würde daher eine fundierte Entscheidung treffen, wenn Sie es oder eine Alternative verwenden möchten. Wenn Sie es dennoch verwenden möchten, finden Sie hier einen Code-Ausschnitt:
Option 5: Google Guava
Meistens haben Sie bereits Guave als Abhängigkeit. Wenn ja, verwenden Sie einfach:
Option 6: Federsicherheit
Wenn Sie das Spring-Framework mit Spring Security verwenden , können Sie Folgendes verwenden:
Option 7: Hüpfburg
Wenn Sie bereits das Sicherheits-Framework Bouncy Castle verwenden , können Sie dessen
Hex
util verwenden:Nicht wirklich Option 8: Java 9+ -Kompatibilität oder 'JAXBs nicht verwenden javax / xml / bind / DatatypeConverter'
In früheren Java-Versionen (8 und niedriger) war der Java-Code für JAXB als Laufzeitabhängigkeit enthalten. Seit Java 9 und Jigsaw Modularisierung Ihr Code ohne explizite Deklaration nicht auf anderen Code außerhalb seines Moduls zugreifen. Seien Sie sich also bewusst, wenn Sie eine Ausnahme erhalten wie:
beim Ausführen auf einer JVM mit Java 9+. Wenn ja, wechseln Sie die Implementierung zu einer der oben genannten Alternativen. Siehe auch dies Frage .
Mikro-Benchmarks
Hier sind die Ergebnisse eines einfachen JMH- Mikro-Benchmarks, der Byte-Arrays unterschiedlicher Größe codiert . Die Werte sind Operationen pro Sekunde, also ist höher besser. Beachten Sie, dass Mikro-Benchmarks sehr oft kein reales Verhalten darstellen. Nehmen Sie diese Ergebnisse daher mit einem Körnchen Salz.
Technische Daten: JDK 8u202, i7-7700K, Win10, 24 GB RAM. Den vollständigen Benchmark finden Sie hier .
quelle
Verwenden Sie die DataTypeConverter-Klasse
javax.xml.bind.DataTypeConverter
String hexString = DatatypeConverter.printHexBinary(bytes[] raw);
quelle
Ich würde so etwas für feste Länge verwenden, wie Hashes:
quelle
Ich habe hier drei verschiedene Möglichkeiten gefunden: http://www.rgagnon.com/javadetails/java-0596.html
Das eleganteste, wie er auch bemerkt, denke ich, ist dieses:
quelle
if (raw == null) return null
ist nicht schnell ausfallen. Warum würden Sie jemals einennull
Schlüssel verwenden?Bei den geringen Kosten für das Speichern der Nachschlagetabelle ist diese Implementierung einfach und sehr schnell.
quelle
BYTE2HEX
Array mit einem einfachenfor
Zyklus initialisieren ?static { }
Block zugewiesen werden .Wie wäre es damit?
quelle
Wir müssen keine externe Bibliothek verwenden oder Code basierend auf Schleifen und Konstanten schreiben.
Ist genug nur das:
quelle
Ich benutze das lieber:
Es ist eine etwas flexiblere Anpassung der akzeptierten Antwort. Persönlich behalte ich sowohl die akzeptierte Antwort als auch diese Überlastung bei, die in mehr Kontexten verwendet werden kann.
quelle
Normalerweise verwende ich die folgende Methode für die Debuf-Anweisung, aber ich weiß nicht, ob dies der beste Weg ist oder nicht
quelle
StringBuilder buf = new StringBuilder(data.length * 2);
.Ok, es gibt eine Reihe von Möglichkeiten, dies zu tun. Wenn Sie sich jedoch für die Verwendung einer Bibliothek entscheiden, würde ich empfehlen, in Ihrem Projekt nachzuschauen, ob in einer Bibliothek, die bereits Teil Ihres Projekts ist, etwas implementiert wurde, bevor Sie eine neue Bibliothek hinzufügen nur um das zu tun. Zum Beispiel, wenn Sie noch nicht haben
Vielleicht hast du ...
quelle
Wenn Sie das Spring Security-Framework verwenden, können Sie Folgendes verwenden:
quelle
Das Hinzufügen eines Utility-JAR für einfache Funktionen ist keine gute Option. Stellen Sie stattdessen Ihre eigenen Dienstprogrammklassen zusammen. Folgendes ist eine schnellere Implementierung möglich.
quelle
Eine kleine Variante der von @maybewecouldstealavan vorgeschlagenen Lösung, mit der Sie N Bytes in der Ausgabe-Hex-Zeichenfolge visuell bündeln können:
Das ist:
quelle
Auf dieser Seite kann keine Lösung gefunden werden, die dies nicht tut
Hier ist eine Lösung, die die oben genannten Mängel nicht aufweist (keine Versprechen, meine hat jedoch keine anderen Mängel)
Ich konnte dies nicht unter 62 Opcodes bekommen, aber wenn Sie ohne 0-Auffüllung leben können, falls das erste Byte kleiner als 0x10 ist, dann verwendet die folgende Lösung nur 23 Opcodes. Zeigt wirklich, wie "einfach, sich selbst zu implementieren" -Lösungen wie "Pad mit einer Null, wenn die Zeichenfolgenlänge ungerade ist" ziemlich teuer werden können, wenn eine native Implementierung noch nicht verfügbar ist (oder in diesem Fall, wenn BigInteger die Option hatte, Nullen vorangestellt zu haben toString).
quelle
Meine Lösung basiert auf der Lösung von MaybeWeCouldStealAVan, basiert jedoch nicht auf zusätzlich zugewiesenen Nachschlagetabellen. Es werden keine "int-to-char" -Cast-Hacks verwendet (tatsächlich wird
Character.forDigit()
ein Vergleich durchgeführt, um zu überprüfen, was die Ziffer wirklich ist) und daher möglicherweise etwas langsamer. Bitte benutzen Sie es, wo immer Sie wollen. Prost.quelle
// Das Verschieben von Bytes ist effizienter // Sie können dieses auch verwenden
quelle
Wenn Sie nach einem genau solchen Byte-Array für Python suchen, habe ich diese Java-Implementierung in Python konvertiert.
quelle
quelle
Hier ist eine
java.util.Base64
ähnliche Implementierung (teilweise), ist es nicht hübsch?quelle
quelle
quelle