Jak zainicjować tablicę bajtów w Javie?

138

Muszę przechowywać pewne wartości stałe (UUID) w postaci tablicy bajtów w java i zastanawiam się, jaki byłby najlepszy sposób na zainicjowanie tych tablic statycznych. Tak właśnie teraz to robię, ale czuję, że musi być lepszy sposób.

private static final byte[] CDRIVES = new byte[] { (byte)0xe0, 0x4f, (byte)0xd0,
    0x20, (byte)0xea, 0x3a, 0x69, 0x10, (byte)0xa2, (byte)0xd8, 0x08, 0x00, 0x2b,
    0x30, 0x30, (byte)0x9d };
private static final byte[] CMYDOCS = new byte[] { (byte)0xba, (byte)0x8a, 0x0d,
    0x45, 0x25, (byte)0xad, (byte)0xd0, 0x11, (byte)0x98, (byte)0xa8, 0x08, 0x00,
    0x36, 0x1b, 0x11, 0x03 };
private static final byte[] IEFRAME = new byte[] { (byte)0x80, 0x53, 0x1c,
    (byte)0x87, (byte)0xa0, 0x42, 0x69, 0x10, (byte)0xa2, (byte)0xea, 0x08,
    0x00, 0x2b, 0x30, 0x30, (byte)0x9d };
...
and so on

Czy jest coś, czego mógłbym użyć, co mogłoby być mniej wydajne, ale wyglądałoby czyściej? na przykład:

private static final byte[] CDRIVES =
    new byte[] { "0xe04fd020ea3a6910a2d808002b30309d" };
dfickling
źródło

Odpowiedzi:

111

byte[]Możesz to zrobić, używając funkcji konwertującej ciąg szesnastkowy na

byte[] CDRIVES = hexStringToByteArray("e04fd020ea3a6910a2d808002b30309d");

Sugerowałbym użycie funkcji zdefiniowanej przez Dave'a L. w Konwersji ciągu reprezentującego zrzut szesnastkowy do tablicy bajtów przy użyciu Javy?

Wstawiam to tutaj dla maksymalnej czytelności:

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

Jeśli pozwolisz CDRIVES statici final, spadek wydajności nie ma znaczenia.

Denys Séguret
źródło
78
byte[] myvar = "Any String you want".getBytes();

Literały łańcuchowe można zastosować w celu zapewnienia dowolnego znaku:

byte[] CDRIVES = "\u00e0\u004f\u00d0\u0020\u00ea\u003a\u0069\u0010\u00a2\u00d8\u0008\u0000\u002b\u0030\u0030\u009d".getBytes();
petmez
źródło
50
Czy to nie zamienia łańcucha "0000"na {0x30,0x30,0x30,0x30}(ASCII) zamiast {0x00,0x00,0x00,0x00}(binarne), zgodnie z życzeniem plakatu?
jww
5
Spójrz na tytuł pytania. Następnie spójrz wstecz na tę odpowiedź. A teraz powiedz mi, co w tym złego? To może nie rozwiązać konkretnego problemu, na który zamieszczono plakat, ale z pewnością rozwiązało moje. Musiałem przekształcić ciąg w tablicę bajtów, aby użyć go jako ziarna dla generatora liczb pseudolosowych, a to działało jak urok.
e18r
@ e18r Generuje bajty, tak, ale nie wiesz które, ponieważ zależy to od domyślnego zestawu znaków. Przynajmniej użyj .getBytes (pożądaneEncoding).
ilość
@petmez głupie pytanie: w JAVA jest coś w rodzaju "" .getBytes (UTF_8)); (getBytes w pustym łańcuchu) bezpieczna rzecz? czy to jest „legalne”? Czy mogę po prostu zrobić: = nowy bajt [0]; ?
Robert Achmann
1
@RobertAchmann "" .getbytes ("UTF-8") powinno zwracać pustą tablicę i jest całkowicie poprawne.
Jazzepi
33

W Javie 6 jest metoda, która robi dokładnie to, co chcesz:

private static final byte[] CDRIVES = javax.xml.bind.DatatypeConverter.parseHexBinary("e04fd020ea3a6910a2d808002b30309d")

Alternatywnie możesz użyć Google Guava :

import com.google.common.io.BaseEncoding;
private static final byte[] CDRIVES = BaseEncoding.base16().lowerCase().decode("E04FD020ea3a6910a2d808002b30309d".toLowerCase());

Metoda Guava to przesada, gdy używasz małych tablic. Ale Guava ma również wersje, które mogą analizować strumienie wejściowe. Jest to fajna funkcja, gdy mamy do czynienia z dużymi danymi szesnastkowymi.

stefan.schwetschke
źródło
Przykład Guava nie działa tak, jak napisano - tak musi być, base16().lowerCase().decode(...)jeśli masz cyfry szesnastkowe z małymi literami. docs.guava-libraries.googlecode.com/git/javadoc/com/google/…
Peter DeGlopper
@PeterDeGlopper Dobre wyniki, zaktualizowałem odpowiedź, więc kod obsługuje teraz ciągi znaków zawierające małe i duże litery.
stefan.schwetschke
1
javax.xml.bindzostał niestety usunięty w Javie 9.
randomdude999
7

Możesz użyć klasy Java UUID do przechowywania tych wartości zamiast tablic bajtowych:

UUID

public UUID(long mostSigBits,
            long leastSigBits)

Konstruuje nowy identyfikator UUID przy użyciu określonych danych. MostSigBits jest używany dla najbardziej znaczących 64 bitów UUID, a najmniejSigBits staje się najmniej znaczącymi 64 bitami UUID.

Jon
źródło
2

Jeśli chodzi o czysty proces, możesz użyć obiektu ByteArrayOutputStream ...

ByteArrayOutputStream bObj = new ByteArrayOutputStream();
bObj.reset();

// zapisz po kolei wszystkie wartości do bObj, używając

bObj.write(byte value)

// kiedy skończysz, możesz pobrać bajt [] używając

CDRIVES = bObj.toByteArray();

// niż możesz powtórzyć podobny proces również dla CMYDOCS i IEFRAME,

UWAGA Nie jest to wydajne rozwiązanie, jeśli masz naprawdę małą macierz.

Amit
źródło
2

Rozwiązanie bez bibliotek, zwracana dynamiczna długość, interpretacja liczb całkowitych bez znaku (nie dopełnienie do dwóch)

    public static byte[] numToBytes(int num){
    if(num == 0){
        return new byte[]{};
    }else if(num < 256){
        return new byte[]{ (byte)(num) };
    }else if(num < 65536){
        return new byte[]{ (byte)(num >>> 8),(byte)num };
    }else if(num < 16777216){
        return new byte[]{ (byte)(num >>> 16),(byte)(num >>> 8),(byte)num };
    }else{ // up to 2,147,483,647
        return new byte[]{ (byte)(num >>> 24),(byte)(num >>> 16),(byte)(num >>> 8),(byte)num };
    }
}
ZMitton
źródło
1

Moją preferowaną opcją w tej sytuacji jest użycie, org.apache.commons.codec.binary.Hexktóry ma przydatne interfejsy API do konwersji z wartości Stringszesnastkowej y na binarną. Na przykład:

  1. Hex.decodeHex(char[] data)który generuje znak, DecoderExceptionjeśli w tablicy znajdują się znaki inne niż szesnastkowe lub jeśli jest nieparzysta liczba znaków.

  2. Hex.encodeHex(byte[] data)jest odpowiednikiem powyższej metody dekodowania i wypluwa plik char[].

  3. Hex.encodeHexString(byte[] data)który konwertuje z powrotem z bytetablicy na plik String.

Stosowanie: Hex.decodeHex("dd645a2564cbe648c8336d2be5eafaa6".toCharArray())

rbrtl
źródło
1

Możesz użyć tej funkcji narzędzia:

public static byte[] fromHexString(String src) {
    byte[] biBytes = new BigInteger("10" + src.replaceAll("\\s", ""), 16).toByteArray();
    return Arrays.copyOfRange(biBytes, 1, biBytes.length);
}

W przeciwieństwie do wariantów Denys Séguret i stefan.schwetschke, umożliwia wstawianie symboli separatorów (spacji, tabulatorów itp.) Do ciągu wejściowego, dzięki czemu jest bardziej czytelny.

Przykład użycia:

private static final byte[] CDRIVES
    = fromHexString("e0 4f d0 20 ea 3a 69 10 a2 d8 08 00 2b 30 30 9d");
private static final byte[] CMYDOCS
    = fromHexString("BA8A0D4525ADD01198A80800361B1103");
private static final byte[] IEFRAME
    = fromHexString("80531c87 a0426910 a2ea0800 2b30309d");
John McClane
źródło
1

Najmniejszy typ wewnętrzny, który w czasie kompilacji może być przypisany liczbami szesnastkowymi to char , as

private static final char[] CDRIVES_char = new char[] {0xe0, 0xf4, ...};

Aby mieć równoważną tablicę bajtów, można wdrożyć konwersje jako

public static byte[] charToByteArray(char[] x)
{
    final byte[] res = new byte[x.length];
    for (int i = 0; i < x.length; i++)
    {
        res[i] = (byte) x[i];
    }
    return res;
}

public static byte[][] charToByteArray(char[][] x)
{
    final byte[][] res = new byte[x.length][];
    for (int i = 0; i < x.length; i++)
    {
        res[i] = charToByteArray(x[i]);
    }
    return res;
}
Sam Ginrich
źródło
-2
private static final int[] CDRIVES = new int[] {0xe0, 0xf4, ...};

a po uzyskaniu dostępu zamień na bajt.

Frankie
źródło