Mam tablicę bajtów wypełnioną liczbami szesnastkowymi i drukowanie jej w prosty sposób jest dość bezcelowe, ponieważ istnieje wiele elementów, które nie mogą zostać wydrukowane. Potrzebuję dokładnego kodu szesnastkowego w postaci:3a5f771c
Mam tablicę bajtów wypełnioną liczbami szesnastkowymi i drukowanie jej w prosty sposób jest dość bezcelowe, ponieważ istnieje wiele elementów, które nie mogą zostać wydrukowane. Potrzebuję dokładnego kodu szesnastkowego w postaci:3a5f771c
Odpowiedzi:
Z dyskusji tutaj , a zwłaszcza z tej odpowiedzi, jest to funkcja, z której obecnie korzystam:
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars);
}
Moje własne małe testy porównawcze (milion bajtów tysiąc razy, 256 bajtów 10 milionów razy) wykazały, że jest on znacznie szybszy niż jakakolwiek inna alternatywa, o połowę krótszy na długich tablicach. W porównaniu z odpowiedzią, z której zacząłem, przejście na operacje bitowe --- jak sugerowano w dyskusji --- skróciło około 20% czasu na długie tablice. (Edycja: Kiedy mówię, że jest szybszy niż alternatywy, mam na myśli alternatywny kod oferowany w dyskusjach. Wydajność jest równoważna kodekowi Commons, który używa bardzo podobnego kodu).
Wersja 2k20 w odniesieniu do kompaktowych ciągów Java 9:
private static final byte[] HEX_ARRAY = "0123456789ABCDEF".toByteArray();
public static String bytesToHex(byte[] bytes) {
byte[] hexChars = new byte[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars, StandardCharsets.UTF_8);
}
String printHexBinary(byte[])
i byte[] parseHexBinary(String)
. printHexBinary
jest jednak znacznie (2x) wolniejszy niż funkcja w tej odpowiedzi. (Sprawdziłem źródło; używa a stringBuilder
. parseHexBinary
Używa tablicy). Naprawdę jednak, dla większości celów jest wystarczająco szybki i prawdopodobnie już go masz.
printHexBinary
?
javax.xml.bind.DataTypeConverter
jest usuwany z Java 11.
Apache Commons Codec biblioteka ma Hex klasę dla robi tylko ten rodzaj pracy.
import org.apache.commons.codec.binary.Hex;
String foo = "I am a string";
byte[] bytes = foo.getBytes();
System.out.println( Hex.encodeHexString( bytes ) );
import org.apache.commons.codec.*;
mógłbyś zrobićimport org.apache.commons.codec.binary.Hex;
org.bouncycastle.util.encoders.Hex
przy użyciu tej metody:String toHexString(byte[] data)
Ta metoda javax.xml.bind.DatatypeConverter.printHexBinary()
, będąca częścią architektury Java Binding XML (JAXB) , była wygodnym sposobem konwersji byte[]
łańcucha szesnastkowego. DatatypeConverter
Klasa zawiera także wiele innych przydatnych metod manipulacji danymi.
W Javie 8 i wcześniejszych JAXB był częścią standardowej biblioteki Java. Został on przestarzały w Javie 9 i usunięty w Javie 11 , w ramach próby przeniesienia wszystkich pakietów Java EE do ich własnych bibliotek. To długa historia . Teraz javax.xml.bind
nie istnieje, a jeśli chcesz użyć JAXB, który zawiera DatatypeConverter
, musisz zainstalować JAXB API i JAXB Runtime z Maven.
Przykładowe użycie:
byte bytes[] = {(byte)0, (byte)0, (byte)134, (byte)0, (byte)61};
String hex = javax.xml.bind.DatatypeConverter.printHexBinary(bytes);
Spowoduje to:
000086003D
Ta odpowiedź jest taka sama jak ta .
Najprostsze rozwiązanie, brak zewnętrznych bibliotek lib, brak cyfr stałych:
public static String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for(byte b: a)
sb.append(String.format("%02x", b));
return sb.toString();
}
Rozwiązanie Guava dla kompletności:
import com.google.common.io.BaseEncoding;
...
byte[] bytes = "Hello world".getBytes(StandardCharsets.UTF_8);
final String hex = BaseEncoding.base16().lowerCase().encode(bytes);
Teraz hex
jest "48656c6c6f20776f726c64"
.
new HashCode(bytes).toString()
.
HashCode.fromBytes(checksum).toString()
Ten prosty oneliner działa dla mnie
String result = new BigInteger(1, inputBytes).toString(16);
EDYCJA - użycie tego spowoduje usunięcie zer wiodących, ale hej działał w moim przypadku użycia. Dzięki @Voicu za zwrócenie na to uwagi
Oto kilka typowych opcji uporządkowanych od prostych (jedno-liniowy) do złożonych (ogromna biblioteka). Jeśli jesteś zainteresowany wydajnością, zapoznaj się z mikro-testami poniżej.
Jednym bardzo prostym rozwiązaniem jest użycie BigInteger
reprezentacji szesnastkowej:
new BigInteger(1, someByteArray).toString(16)
Zauważ, że ponieważ obsługuje liczby, które nie są dowolnymi ciągami bajtów , pominie zera wiodące - może to być lub nie być to, czego chcesz (np. 000AE3
Vs 0AE3
dla danych 3-bajtowych). Jest to również bardzo wolne, około 100 razy wolniejsze w porównaniu do następnej opcji.
Oto w pełni funkcjonalny, kopiowany i wklejany fragment kodu obsługujący wielkie / małe litery oraz endianness . Jest zoptymalizowany, aby zminimalizować złożoność pamięci i zmaksymalizować wydajność i powinien być kompatybilny ze wszystkimi nowoczesnymi wersjami Java (5+).
private static final char[] LOOKUP_TABLE_LOWER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
private static final char[] LOOKUP_TABLE_UPPER = new char[]{0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
public static String encode(byte[] byteArray, boolean upperCase, ByteOrder byteOrder) {
// our output size will be exactly 2x byte-array length
final char[] buffer = new char[byteArray.length * 2];
// choose lower or uppercase lookup table
final char[] 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)];
}
return new String(buffer);
}
public static String encode(byte[] byteArray) {
return encode(byteArray, false, ByteOrder.BIG_ENDIAN);
}
Pełny kod źródłowy z licencją i dekoderem Apache v2 można znaleźć tutaj .
Pracując nad poprzednim projektem, stworzyłem ten mały zestaw narzędzi do pracy z bajtami w Javie. Nie ma zewnętrznych zależności i jest kompatybilny z Javą 7+. Obejmuje między innymi bardzo szybki i dobrze przetestowany dekoder / dekoder HEX:
import at.favre.lib.bytes.Bytes;
...
Bytes.wrap(someByteArray).encodeHex()
Możesz to sprawdzić na Github: bytes-java .
Oczywiście są dobre kodeki wspólne . ( opinia ostrzegawcza przed nami ) Podczas pracy nad projektem opisanym powyżej przeanalizowałem kod i byłem bardzo rozczarowany; wiele zduplikowanych niezorganizowanych kodów, przestarzałe i egzotyczne kodeki są prawdopodobnie przydatne tylko dla bardzo nielicznych i dość skomplikowanych i powolnych implementacji popularnych kodeków (szczególnie Base64). W związku z tym podjąłbym świadomą decyzję, jeśli chcesz skorzystać z niej lub z alternatywy. W każdym razie, jeśli nadal chcesz go używać, oto fragment kodu:
import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(someByteArray));
Najczęściej masz Guava jako zależność. Jeśli tak, użyj:
import com.google.common.io.BaseEncoding;
...
BaseEncoding.base16().lowerCase().encode(someByteArray);
Jeśli korzystasz ze struktury Spring z Spring Security , możesz użyć następujących opcji:
import org.springframework.security.crypto.codec.Hex
...
new String(Hex.encode(someByteArray));
Jeśli korzystasz już z ram bezpieczeństwa Bouncy Castle , możesz użyć jego wykorzystania Hex
:
import org.bouncycastle.util.encoders.Hex;
...
Hex.toHexString(someByteArray);
W poprzednich wersjach Java (8 i niższych) kod Java dla JAXB był dołączany jako zależność środowiska wykonawczego. Od modularyzacji Java 9 i Jigsaw Twój kod nie może uzyskać dostępu do innego kodu poza modułem bez wyraźnej deklaracji. Więc pamiętaj, jeśli otrzymasz wyjątek, taki jak:
java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
podczas pracy na JVM z Javą 9+. Jeśli tak, przełącz implementacje na dowolne z powyższych rozwiązań. Zobacz także to pytanie .
Oto wyniki z prostego macierzy bajtowej JMH do mikro-testów o różnych rozmiarach . Wartości są operacjami na sekundę, więc im wyższa, tym lepiej. Zauważ, że mikroskopy bardzo często nie reprezentują zachowania w świecie rzeczywistym, więc weź te wyniki z odrobiną soli.
| Name (ops/s) | 16 byte | 32 byte | 128 byte | 0.95 MB |
|----------------------|-----------:|-----------:|----------:|--------:|
| Opt1: BigInteger | 2,088,514 | 1,008,357 | 133,665 | 4 |
| Opt2/3: Bytes Lib | 20,423,170 | 16,049,841 | 6,685,522 | 825 |
| Opt4: Apache Commons | 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 |
Specyfikacja: JDK 8u202, i7-7700K, Win10, 24 GB RAM. Zobacz pełny test tutaj .
Użyj klasy DataTypeConverterjavax.xml.bind.DataTypeConverter
String hexString = DatatypeConverter.printHexBinary(bytes[] raw);
Użyłbym czegoś takiego dla stałej długości, np. Skrótów:
md5sum = String.format("%032x", new BigInteger(1, md.digest()));
Znalazłem tutaj trzy różne sposoby: http://www.rgagnon.com/javadetails/java-0596.html
Najbardziej elegancki, jak zauważa, myślę, że jest ten:
static final String HEXES = "0123456789ABCDEF";
public static String getHex( byte [] raw ) {
if ( raw == null ) {
return null;
}
final StringBuilder hex = new StringBuilder( 2 * raw.length );
for ( final byte b : raw ) {
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
if (raw == null) return null
nie zawiedzie szybko. Dlaczego miałbyś kiedykolwiek używać null
klucza?
Przy niewielkich kosztach przechowywania tabeli odnośników ta implementacja jest prosta i bardzo szybka.
private static final char[] BYTE2HEX=(
"000102030405060708090A0B0C0D0E0F"+
"101112131415161718191A1B1C1D1E1F"+
"202122232425262728292A2B2C2D2E2F"+
"303132333435363738393A3B3C3D3E3F"+
"404142434445464748494A4B4C4D4E4F"+
"505152535455565758595A5B5C5D5E5F"+
"606162636465666768696A6B6C6D6E6F"+
"707172737475767778797A7B7C7D7E7F"+
"808182838485868788898A8B8C8D8E8F"+
"909192939495969798999A9B9C9D9E9F"+
"A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"+
"B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"+
"C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"+
"D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"+
"E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"+
"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF").toCharArray();
;
public static String getHexString(byte[] bytes) {
final int len=bytes.length;
final char[] chars=new char[len<<1];
int hexIndex;
int idx=0;
int ofs=0;
while (ofs<len) {
hexIndex=(bytes[ofs++] & 0xFF)<<1;
chars[idx++]=BYTE2HEX[hexIndex++];
chars[idx++]=BYTE2HEX[hexIndex];
}
return new String(chars);
}
BYTE2HEX
tablicy za pomocą prostego for
cyklu?
static { }
bloku.
Co powiesz na to?
String byteToHex(final byte[] hash)
{
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
Wolę użyć tego:
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes, int offset, int count) {
char[] hexChars = new char[count * 2];
for ( int j = 0; j < count; j++ ) {
int v = bytes[j+offset] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
Jest to nieco bardziej elastyczne dostosowanie przyjętej odpowiedzi. Osobiście zachowuję zarówno akceptowaną odpowiedź, jak i to przeciążenie wraz z nią, do użytku w większej liczbie kontekstów.
Zwykle używam następującej metody do instrukcji debuf, ale nie wiem, czy jest to najlepszy sposób, czy nie
private static String digits = "0123456789abcdef";
public static String toHex(byte[] data){
StringBuffer buf = new StringBuffer();
for (int i = 0; i != data.length; i++)
{
int v = data[i] & 0xff;
buf.append(digits.charAt(v >> 4));
buf.append(digits.charAt(v & 0xf));
}
return buf.toString();
}
StringBuilder buf = new StringBuilder(data.length * 2);
.
Ok, więc istnieje wiele sposobów, aby to zrobić, ale jeśli zdecydujesz się użyć biblioteki, radzę zajrzeć do twojego projektu, aby sprawdzić, czy coś zostało zaimplementowane w bibliotece, która jest już częścią twojego projektu przed dodaniem nowej biblioteki po prostu to zrobić. Na przykład, jeśli jeszcze tego nie masz
org.apache.commons.codec.binary.Hex
może masz ...
org.apache.xerces.impl.dv.util.HexBin
Jeśli korzystasz ze środowiska Spring Security, możesz użyć:
import org.springframework.security.crypto.codec.Hex
final String testString = "Test String";
final byte[] byteArray = testString.getBytes();
System.out.println(Hex.encode(byteArray));
Dodanie słoika narzędziowego dla prostej funkcji nie jest dobrą opcją. Zamiast tego montuj własne klasy narzędzi. możliwe jest szybsze wdrożenie.
public class ByteHex {
public static int hexToByte(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 String[] byteToHexTable = new String[]
{
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
};
private static final String[] byteToHexTableLowerCase = new String[]
{
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
"b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df",
"e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff"
};
public static String byteToHex(byte b){
return byteToHexTable[b & 0xFF];
}
public static String byteToHex(byte[] bytes){
if(bytes == null) return null;
StringBuilder sb = new StringBuilder(bytes.length*2);
for(byte b : bytes) sb.append(byteToHexTable[b & 0xFF]);
return sb.toString();
}
public static String byteToHex(short[] bytes){
StringBuilder sb = new StringBuilder(bytes.length*2);
for(short b : bytes) sb.append(byteToHexTable[((byte)b) & 0xFF]);
return sb.toString();
}
public static String byteToHexLowerCase(byte[] bytes){
StringBuilder sb = new StringBuilder(bytes.length*2);
for(byte b : bytes) sb.append(byteToHexTableLowerCase[b & 0xFF]);
return sb.toString();
}
public static byte[] hexToByte(String hexString) {
if(hexString == null) return null;
byte[] byteArray = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i += 2) {
byteArray[i / 2] = (byte) (hexToByte(hexString.charAt(i)) * 16 + hexToByte(hexString.charAt(i+1)));
}
return byteArray;
}
public static byte hexPairToByte(char ch1, char ch2) {
return (byte) (hexToByte(ch1) * 16 + hexToByte(ch2));
}
}
Mały wariant rozwiązania zaproponowanego przez @maybewecouldstealavan, który pozwala wizualnie łączyć N bajtów razem w wyjściowym ciągu szesnastkowym:
final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
final static char BUNDLE_SEP = ' ';
public static String bytesToHexString(byte[] bytes, int bundleSize /*[bytes]*/]) {
char[] hexChars = new char[(bytes.length * 2) + (bytes.length / bundleSize)];
for (int j = 0, k = 1; j < bytes.length; j++, k++) {
int v = bytes[j] & 0xFF;
int start = (j * 2) + j/bundleSize;
hexChars[start] = HEX_ARRAY[v >>> 4];
hexChars[start + 1] = HEX_ARRAY[v & 0x0F];
if ((k % bundleSize) == 0) {
hexChars[start + 2] = BUNDLE_SEP;
}
}
return new String(hexChars).trim();
}
To jest:
bytesToHexString("..DOOM..".toCharArray().getBytes(), 2);
2E2E 444F 4F4D 2E2E
bytesToHexString("..DOOM..".toCharArray().getBytes(), 4);
2E2E444F 4F4D2E2E
Nie mogę znaleźć na tej stronie żadnego rozwiązania, które by tego nie zrobiło
Oto rozwiązanie, które nie ma wad powyżej (żadne moje obietnice nie mają innych wad)
import java.math.BigInteger;
import static java.lang.System.out;
public final class App2 {
// | proposed solution.
public static String encode(byte[] bytes) {
final int length = bytes.length;
// | BigInteger constructor throws if it is given an empty array.
if (length == 0) {
return "00";
}
final int evenLength = (int)(2 * Math.ceil(length / 2.0));
final String format = "%0" + evenLength + "x";
final String result = String.format (format, new BigInteger(bytes));
return result;
}
public static void main(String[] args) throws Exception {
// 00
out.println(encode(new byte[] {}));
// 01
out.println(encode(new byte[] {1}));
//203040
out.println(encode(new byte[] {0x20, 0x30, 0x40}));
// 416c6c20796f75722062617365206172652062656c6f6e6720746f2075732e
out.println(encode("All your base are belong to us.".getBytes()));
}
}
Nie udało mi się uzyskać tego pod 62 kodami, ale jeśli możesz żyć bez zerowania w przypadku, gdy pierwszy bajt jest mniejszy niż 0x10, poniższe rozwiązanie używa tylko 23 kodów. Naprawdę pokazuje, jak rozwiązania „łatwe do samodzielnego wdrożenia”, takie jak „pad z zerem, jeśli długość łańcucha jest nieparzysta”, mogą stać się dość drogie, jeśli natywna implementacja nie jest już dostępna (lub w tym przypadku, jeśli BigInteger miał opcję prefiksu zerami w toString).
public static String encode(byte[] bytes) {
final int length = bytes.length;
// | BigInteger constructor throws if it is given an empty array.
if (length == 0) {
return "00";
}
return new BigInteger(bytes).toString(16);
}
Moje rozwiązanie jest oparte na rozwiązaniu możeWeCouldStealAVan, ale nie opiera się na żadnych dodatkowych tabelach wyszukiwania. Nie używa hacków typu int-to-char (w rzeczywistości Character.forDigit()
robi to, porównując, aby sprawdzić, czym naprawdę jest cyfra), a zatem może być nieco wolniejszy. Możesz go używać gdziekolwiek chcesz. Twoje zdrowie.
public static String bytesToHex(final byte[] bytes)
{
final int numBytes = bytes.length;
final char[] container = new char[numBytes * 2];
for (int i = 0; i < numBytes; i++)
{
final int b = bytes[i] & 0xFF;
container[i * 2] = Character.forDigit(b >>> 4, 0x10);
container[i * 2 + 1] = Character.forDigit(b & 0xF, 0x10);
}
return new String(container);
}
Jeśli szukasz tablicy bajtów dokładnie takiej jak dla Pythona, przekonwertowałem tę implementację Java na python.
class ByteArray:
@classmethod
def char(cls, args=[]):
cls.hexArray = "0123456789ABCDEF".encode('utf-16')
j = 0
length = (cls.hexArray)
if j < length:
v = j & 0xFF
hexChars = [None, None]
hexChars[j * 2] = str( cls.hexArray) + str(v)
hexChars[j * 2 + 1] = str(cls.hexArray) + str(v) + str(0x0F)
# Use if you want...
#hexChars.pop()
return str(hexChars)
array = ByteArray()
print array.char(args=[])
Oto java.util.Base64
implementacja przypominająca (częściowa), prawda?
public class Base16/*a.k.a. Hex*/ {
public static class Encoder{
private static char[] toLowerHex={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
private static char[] toUpperHex={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
private boolean upper;
public Encoder(boolean upper) {
this.upper=upper;
}
public String encode(byte[] data){
char[] value=new char[data.length*2];
char[] toHex=upper?toUpperHex:toLowerHex;
for(int i=0,j=0;i<data.length;i++){
int octet=data[i]&0xFF;
value[j++]=toHex[octet>>4];
value[j++]=toHex[octet&0xF];
}
return new String(value);
}
static final Encoder LOWER=new Encoder(false);
static final Encoder UPPER=new Encoder(true);
}
public static Encoder getEncoder(){
return Encoder.LOWER;
}
public static Encoder getUpperEncoder(){
return Encoder.UPPER;
}
//...
}
private static String bytesToHexString(byte[] bytes, int length) {
if (bytes == null || length == 0) return null;
StringBuilder ret = new StringBuilder(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();
}
Converts bytes data to hex characters
@param bytes byte array to be converted to hex string
@return byte String in hex format
private static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
int v;
for (int j = 0; j < bytes.length; j++) {
v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars);
}
toHexString(...)
metodę, która może pomóc, jeśli tego właśnie szukasz.String.format(...)
Można także wykonać kilka sztuczek formatowania przy użyciu ciągu%2x
kodu.