Hoe een byte-array converteren naar een zeskantstring in Java?

Ik heb een byte array gevuld met hex-nummers en het afdrukken op de gemakkelijke manier is vrij zinloos omdat er veel onprakkelijke elementen zijn. Wat ik nodig heb, is de exacte hexcode in de vorm van: 3a5f771c


Antwoord 1, Autoriteit 100%

van de discussie hier , en vooral Dit antwoord, dit is de functie die ik momenteel gebruik:

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

Mijn eigen kleine benchmarks (een miljoen bytes duizend keer, 256 bytes 10 miljoen keer) liet het zien dat het veel sneller is dan enig ander alternatief, ongeveer de helft van de tijd op lange arrays. In vergelijking met het antwoord nam ik het van, om over te schakelen naar bitwise ops — zoals gesuggereerd in de discussie — Snijd ongeveer 20% korting op de tijd voor lange arrays. (Bewerken: wanneer ik zeg dat het sneller is dan de alternatieven, bedoel ik de alternatieve code die in de discussies wordt aangeboden. De prestaties zijn equivalent aan Commons-codec, die een vergelijkbare code gebruikt.)

2K20-versie, met betrekking tot Java 9 Compacte snaren:

private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
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);
}

Antwoord 2, autoriteit 49%

De Apache Commons Codec-bibliotheek heeft een Hexklasse voor het doen van precies dit soort werk.

import org.apache.commons.codec.binary.Hex;
String foo = "I am a string";
byte[] bytes = foo.getBytes();
System.out.println( Hex.encodeHexString( bytes ) );

Antwoord 3, autoriteit 34%

De methode javax.xml.bind.DatatypeConverter.printHexBinary(), onderdeel van de Java Architecture for XML Binding (JAXB), was een handige manier om een byte[]naar een hex-tekenreeks te converteren. De DatatypeConverterklasse bevatte ook veel andere nuttige methoden voor gegevensmanipulatie.

In Java 8 en eerder maakte JAXB deel uit van de Java-standaardbibliotheek. Het was verouderdmet Java 9 en verwijderdmet Java 11, als onderdeel van een poging om alle Java EE-pakketten naar hun eigen bibliotheken te verplaatsen. Het is een lang verhaal. Nu bestaat javax.xml.bindniet, en als je JAXB wilt gebruiken, dat DatatypeConverterbevat, moet je de JAXB APIen JAXB Runtimevan Maven.

Voorbeeld van gebruik:

byte bytes[] = {(byte)0, (byte)0, (byte)134, (byte)0, (byte)61};
String hex = javax.xml.bind.DatatypeConverter.printHexBinary(bytes);

Zal resulteren in:

000086003D

Dit antwoord hetzelfde als deze.


Antwoord 4, autoriteit 26%

Eenvoudigste oplossing, geen externe bibliotheken, geen cijferconstanten:

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

Antwoord 5, autoriteit 8%

Hier zijn enkele algemene opties die zijn besteld bij Simple (one-liner) tot complexe (enorme bibliotheek). Als u geïnteresseerd bent in de prestaties, raadpleegt u de onderstaande micro-benchmarks.

Optie 1: Code Snippet – eenvoudig (alleen met JDK / Android)

Optie 1A: BIGINTEGER

Een zeer eenvoudige oplossing is om de BigInteger‘S HEX-vertegenwoordiging te gebruiken:

new BigInteger(1, someByteArray).toString(16);

Merk op dat sinds deze handgrepen nummers niet arbitrair byte-strings Wordt voorloopnullen – dit kan al dan niet zijn wat u wilt (bijv. 000AE3versus 0AE3voor een ingang van 3 byte). Dit is ook erg traag, ongeveer 100x langzamer in vergelijking met optie 2.

Optie 1b: string.Format ()

Gebruik van de %XPlaceholder, String.format()kan de meeste primitieve typen coderen (short, int, long) naar HEX:

String.format("%X", ByteBuffer.wrap(eightByteArray).getLong());

Optie 1c: geheel getal / lang (slechts 4/8 byte arrays)

Als u uitsluitend 4 bytes-arrays hebt U kunt de toHexStringmethode van de integer klasse:

Integer.toHexString(ByteBuffer.wrap(fourByteArray).getInt());

Dezelfde werken met 8 byte arrays en long

Long.toHexString(ByteBuffer.wrap(eightByteArray).getLong());

Optie 2: Codefragment – Geavanceerd

Hier is een volledige, kopie & plakbaar codefragment met ondersteuning voor hoofdletters/kleine lettersen endianness. Het is geoptimaliseerd om de geheugencomplexiteit te minimaliseren en de prestaties te maximaliseren en zou compatibel moeten zijn met alle moderne Java-versies (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);
}

De volledige broncode met Apache v2-licentie en decoder is hierte vinden.

Optie 3: Een kleine geoptimaliseerde bibliotheek gebruiken: bytes-java

Terwijl ik aan mijn vorige project werkte, heb ik deze kleine toolkit gemaakt voor het werken met bytes in Java. Het heeft geen externe afhankelijkheden en is compatibel met Java 7+. Het bevat onder andere een zeer snelle en goed geteste HEX en/decoder:

import at.favre.lib.bytes.Bytes;
...
Bytes.wrap(someByteArray).encodeHex()

Je kunt het bekijken op Github: bytes-java.

Optie 4: Apache Commons Codec

Natuurlijk zijn er de goede commons-codecs. (waarschuwing vooruit) Terwijl ik aan het hierboven beschreven project werkte, analyseerde ik de code en was behoorlijk teleurgesteld; veel dubbele ongeorganiseerde code, verouderde en exotische codecs die waarschijnlijk alleen nuttig zijn voor zeer weinig en behoorlijk overontwikkelde en langzame implementaties van populaire codecs (met name Base64). Ik zou daarom een weloverwogen beslissing nemen als je het of een alternatief wilt gebruiken.Hoe dan ook, als je het nog steeds wilt gebruiken, hier is een codefragment:

import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(someByteArray));

Optie 5: Google Guava

Vaak heeft u al Guave als afhankelijkheid. Zo ja, gebruik dan:

import com.google.common.io.BaseEncoding;
...
BaseEncoding.base16().lowerCase().encode(someByteArray);

Optie 6: Veerbeveiliging

Als u de veer raamwerk met Spring Security U kunt het volgende gebruiken:

import org.springframework.security.crypto.codec.Hex
...
new String(Hex.encode(someByteArray));

Optie 7: Bouncy Castle

Als u het beveiligingsramework Bouncy Castle U kunt zijn Hexgebruiken util:

import org.bouncycastle.util.encoders.Hex;
...
Hex.toHexString(someByteArray);

Niet echt optie 8: Java 9+ Compatibiliteit of ‘Gebruik geen JAXBS JAVAX / XML / BIND / DATATYPECONVERTER’

In vorige Java (8 en onder) werden versies de Java-code voor JAXB opgenomen als runtime-afhankelijkheid. Sinds Java 9 en Jigsaw Modularisation Uw code heeft geen andere code buiten toegang van de module zonder expliciete verklaring. Dus let op als u een uitzondering krijgt zoals:

java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

Bij het uitvoeren van een JVM met Java 9+. Als dit het geval is, schakelt u de implementaties in op een van de bovenstaande alternatieven. Zie ook dit vraag .


Micro Benchmarks

Hier zijn resultaten van een eenvoudige jmh micro-benchmark die codeert byte arrays met verschillende maten . De waarden zijn operaties per seconde, dus hoger is beter.
Merk op dat micro-benchmarks vaak geen echte wereldgedrag vertegenwoordigen, dus neem deze resultaten mee met een korrel van zout.

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

Specs: JDK 8U202, I7-7700K, WIN10, 24GB RAM. Zie de volledige benchmark hier .


Antwoord 6, Autoriteit 7%

Een Guave-oplossing, voor volledigheid:

import com.google.common.io.BaseEncoding;
...
byte[] bytes = "Hello world".getBytes(StandardCharsets.UTF_8);
final String hex = BaseEncoding.base16().lowerCase().encode(bytes);

Nu Hexis "48656c6c6f20776f726c64"


Antwoord 7, Autoriteit 5%

Deze eenvoudige oneliner werkt voor mij
String result = new BigInteger(1, inputBytes).toString(16);
EDIT – Als u dit gebruikt, worden de voorloopnullen verwijderd, maar hey werkte voor mijn use-case. Bedankt @Voicu voor het erop wijzen


Antwoord 8, autoriteit 3%

Gebruik DataTypeConverter-klassejavax.xml.bind.DataTypeConverter

String hexString = DatatypeConverter.printHexBinary(bytes[] raw);


Antwoord 9, autoriteit 2%

Ik zou zoiets als dit gebruiken voor een vaste lengte, zoals hashes:

md5sum = String.format("%032x", new BigInteger(1, md.digest()));

Antwoord 10, autoriteit 2%

Ik heb hier drie verschillende manieren gevonden:
http://www.rgagnon.com/javadetails/java-0596.html

De meest elegante, zoals hij ook opmerkt, is volgens mij deze:

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

Antwoord 11, autoriteit 2%

Tegen de kleine kosten van het opslaan van de opzoektabel is deze implementatie eenvoudig en erg snel.

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

Antwoord 12

Wat dacht je hiervan?

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

Antwoord 13

We hoeven geen externe bibliotheek te gebruiken of code te schrijven op basis van lussen en constanten.
Is alleen dit genoeg:

byte[] theValue = .....
String hexaString = new BigInteger(1, theValue).toString(16);

Antwoord 14

Het toevoegen van een hulpprogramma-pot voor een eenvoudige functie is geen goede optie. Stel in plaats daarvan uw eigen hulpprogrammaklassen samen. volgende is mogelijk snellere implementatie.

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

Antwoord 15

Als u het Spring Security-framework gebruikt, kunt u het volgende gebruiken:

import org.springframework.security.crypto.codec.Hex
final String testString = "Test String";
final byte[] byteArray = testString.getBytes();
System.out.println(Hex.encode(byteArray));

Antwoord 16

Ik gebruik dit liever:

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

Het is iets flexibeler aanpassing van het geaccepteerde antwoord.
Persoonlijk bewaar ik zowel het geaccepteerde antwoord als deze overbelasting daarmee, bruikbaar in meer contexten.


Antwoord 17

Ik gebruik meestal de volgende methode voor Debuf-verklaring, maar ik weet niet of het de beste manier is om het te doen of niet

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

Antwoord 18

OK, dus er zijn een aantal manieren om dit te doen, maar als u besluit om een ​​bibliotheek te gebruiken, zou ik voorstellen in uw project om te zien of er iets is geïmplementeerd in een bibliotheek die al deel uitmaakt van uw project voordat u toevoegt een nieuwe bibliotheek om dit te doen. Bijvoorbeeld als u zich niet

hebt

org.apache.commons.codec.binary.hex

Misschien heb je wel …

org.apache.xerces.impl.dv.util.hexbin


Antwoord 19

public static String toHexString(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    if (bytes != null) 
        for (byte b:bytes) {
            final String hexString = Integer.toHexString(b & 0xff);
            if(hexString.length()==1)
                sb.append('0');
            sb.append(hexString);//.append(' ');
        }
      return sb.toString();//.toUpperCase();
}

DatatypeConverter gebruiken:

public String toHexString(byte... bytes) {
    return Optional.ofNullable(bytes)
            .filter(bs->bs.length>0)
            .map(DatatypeConverter::printHexBinary)
            .map(str->IntStream.range(0, str.length())
                    .filter(i->(i%2)==0)        // take every second index
                    .mapToObj(i->"0x" + str.substring(i, i+2))
                    .collect(Collectors.joining(" ")))
            .orElse("");
}

Antwoord 20

Een kleine variant van de oplossing voorgesteld door @maybewecouldstealavan, waarmee je N bytes visueel kunt bundelen in de output hex string:

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

Dat is:

bytesToHexString("..DOOM..".toCharArray().getBytes(), 2);
2E2E 444F 4F4D 2E2E
bytesToHexString("..DOOM..".toCharArray().getBytes(), 4);
2E2E444F 4F4D2E2E

Antwoord 21

Kan op deze pagina geen oplossing vinden die dat niet doet

  1. Gebruik een lus
  2. Gebruik javax.xml.bind.DatatypeConverter die prima compileert maar vaak java.lang.NoClassDefFoundError tijdens runtime genereert.

Hier is een oplossing die de bovenstaande gebreken niet heeft (geen beloftes, de mijne heeft echter geen andere gebreken)

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

Ik kon dit niet krijgen onder 62 opcodes, maar als je kunt leven zonder 0 vulling in het geval de eerste byte kleiner is dan 0x10, gebruikt de volgende oplossing slechts 23 opcodes. Toont echt hoe “gemakkelijk om uzelf te implementeren” oplossingen zoals “pad met een nul als een stringlengte vreemd is” kan behoorlijk duur worden als een inheemse implementatie nog niet beschikbaar is (of in dit geval, als Biginteger een optie had om met nullen in te vullen 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);
}

Antwoord 22

Mijn oplossing is gebaseerd op de oplossing van Maybewecouldaleavan, maar vertrouwt niet op elke toegewezen lookuptafels. Het gebruikt geen ‘int-to-char’ casts hacks (eigenlijk, Character.forDigit()doet het, wat een vergelijking uit te voeren om te controleren wat het cijfer echt is) en dus misschien een beetje langzamer is . Aarzel niet om het te gebruiken waar je maar wilt. Proost.

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

Antwoord 23

Hier is nog een andere methode met behulp van streams:

private static String toHexString(byte[] bytes) {
    return IntStream.range(0, bytes.length)
    .mapToObj(i -> String.format("%02X", bytes[i]))
    .collect(Collectors.joining());
}

Antwoord 24

Hier is een java.util.Base64-achtige implementatie, is het niet mooi?

import java.util.Arrays;
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_CASE=new Encoder(false);
        static final Encoder UPPER_CASE=new Encoder(true);
    }
    public static Encoder getEncoder(){
        return Encoder.LOWER_CASE;
    }
    public static Encoder getUpperEncoder(){
        return Encoder.UPPER_CASE;
    }
    public static class Decoder{
      private static int maxIndex=102;
      private static int[] toIndex;
      static {
        toIndex=new int[maxIndex+1];
        Arrays.fill(toIndex, -1);
        char[] chars={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','a','b','c','d','e','f'};
        for(int i=0; i<chars.length; i++) {
          toIndex[(int)chars[i]]=i;
        }
      }
      public Decoder() {
      }
      public byte[] decode(String str) {
          char[] value=str.toCharArray();
          int start=0;
          if(value.length>2 && value[0]=='0' && (value[1]=='x' || value[1]=='X')) {
            start=2;
          }
          int byteLength=(value.length-start)/2; // ignore trailing odd char if exists
          byte[] data=new byte[byteLength];
          for(int i=start,j=0;i<value.length;i+=2,j++){
              int i1;
              int i2;
              char c1=value[i];
              char c2=value[i+1];
              if(c1>maxIndex || (i1=toIndex[(int)c1])<0 || c2>maxIndex || (i2=toIndex[(int)c2])<0) {
                throw new IllegalArgumentException("Invalid character at "+i);
              }
              data[j]=(byte)((i1<<4)+i2);
          }
          return data;
      }
      static final Decoder IGNORE_CASE=new Decoder();
  }
  public static Decoder getDecoder(){
      return Decoder.IGNORE_CASE;
  }
}

Antwoord 25

// Het verschuiven van bytes is efficiënter
// Je kunt deze ook gebruiken

public static String getHexString (String s) 
{
    byte[] buf = s.getBytes();
    StringBuffer sb = new StringBuffer();
    for (byte b:buf)
    {
        sb.append(String.format("%x", b));
    }
        return sb.toString();
}

Antwoord 26

Als u op zoek bent naar een byte-array precies zoals deze voor python, heb ik deze Java-implementatie omgezet in 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=[])

Antwoord 27

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

Antwoord 28

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

Antwoord 29

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

Other episodes