Bagaimana cara menginisialisasi array byte di Java?

146

Saya harus menyimpan beberapa nilai konstan (UUID) dalam bentuk array byte di java, dan saya bertanya-tanya apa cara terbaik untuk menginisialisasi array statis tersebut. Beginilah cara saya saat ini melakukannya, tetapi saya merasa pasti ada cara yang lebih baik.

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

Adakah yang bisa saya gunakan yang mungkin kurang efisien, tetapi akan terlihat lebih bersih? sebagai contoh:

private static final byte[] CDRIVES =
    new byte[] { "0xe04fd020ea3a6910a2d808002b30309d" };
dfickling
sumber

Jawaban:

117

Menggunakan fungsi yang mengubah string heksa menjadi byte[], Anda bisa melakukannya

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

Saya sarankan Anda menggunakan fungsi yang ditentukan oleh Dave L dalam Mengkonversi representasi string dari hex dump ke array byte menggunakan Java?

Saya memasukkannya di sini untuk keterbacaan maksimum:

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

Jika Anda membiarkan CDRIVES staticdan final, penurunan kinerja tidak relevan.

Denys Séguret
sumber
79
byte[] myvar = "Any String you want".getBytes();

String literal dapat di-escape untuk memberikan karakter apa pun:

byte[] CDRIVES = "\u00e0\u004f\u00d0\u0020\u00ea\u003a\u0069\u0010\u00a2\u00d8\u0008\u0000\u002b\u0030\u0030\u009d".getBytes();
petmez.dll
sumber
51
Bukankah itu mengubah string "0000"menjadi {0x30,0x30,0x30,0x30}(ASCII) daripada {0x00,0x00,0x00,0x00}(biner) seperti yang diinginkan oleh poster?
jww
5
Lihat judul pertanyaannya. Kemudian lihat kembali jawaban ini. Sekarang katakan padaku, apa yang salah tentang itu? Ini mungkin tidak menyelesaikan masalah khusus poster, tapi pasti menyelesaikan masalah saya. Saya perlu mengubah string menjadi array byte untuk digunakan sebagai benih untuk generator nomor pseudorandom dan ini bekerja seperti pesona.
e18r
@ e18r Ini menghasilkan byte, ya, tetapi Anda tidak tahu yang mana karena ini bergantung pada charset default. Setidaknya gunakan .getBytes (diinginkanEncoding).
Kuantitas
@petmez pertanyaan bodoh: di JAVA, adalah sesuatu seperti "" .getBytes (UTF_8)); (getBytes pada string kosong) hal yang aman untuk dilakukan? apakah itu 'legal'? Atau dapatkah saya melakukan: = new byte [0]; ?
Robert Achmann
1
@RobertAchmann "" .getbytes ("UTF-8") harus mengembalikan larik kosong dan benar-benar legal.
Jazzepi
34

Di Java 6, ada metode yang melakukan apa yang Anda inginkan:

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

Atau Anda bisa menggunakan Google Guava :

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

Metode Guava berlebihan, jika Anda menggunakan array kecil. Tetapi Guava juga memiliki versi yang dapat mengurai aliran input. Ini adalah fitur yang bagus saat berhadapan dengan input heksadesimal yang besar.

stefan.schwetschke
sumber
Contoh Guava tidak berfungsi seperti yang tertulis - ini harus dilakukan base16().lowerCase().decode(...)jika Anda memiliki digit hex huruf kecil. docs.guava-libraries.googlecode.com/git/javadoc/com/google/…
Peter DeGlopper
@PeterDeGlopper Temuan bagus, saya telah memperbarui jawabannya sehingga kode sekarang menangani string dengan karakter huruf kecil dan besar.
stefan.schwetschke
1
javax.xml.bindsayangnya dihapus di Jawa 9.
randomdude999
7

Anda dapat menggunakan kelas UUID Java untuk menyimpan nilai-nilai ini, sebagai ganti array byte:

UUID

public UUID(long mostSigBits,
            long leastSigBits)

Membuat UUID baru menggunakan data yang ditentukan. mostSigBits digunakan untuk 64 bit UUID yang paling signifikan dan leastSigBits menjadi 64 bit UUID yang paling signifikan.

Jon
sumber
3

Solusi tanpa pustaka, panjang dinamis dikembalikan, interpretasi integer tak bertanda tangan (bukan pelengkap dua)

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

Sejauh menyangkut proses bersih, Anda dapat menggunakan objek ByteArrayOutputStream ...

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

// tulis semua nilai ke bObj satu per satu menggunakan

bObj.write(byte value)

// setelah selesai Anda bisa mendapatkan byte [] menggunakan

CDRIVES = bObj.toByteArray();

// daripada Anda dapat mengulangi proses serupa untuk CMYDOCS dan IEFRAME juga,

CATATAN Ini bukan solusi yang efisien jika Anda benar-benar memiliki larik kecil.

Amit
sumber
2

Tipe internal terkecil, yang pada waktu kompilasi dapat ditentukan oleh bilangan hex adalah char , as

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

Untuk memiliki array byte yang setara, seseorang dapat menerapkan konversi sebagai

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

Pilihan saya yang lebih disukai dalam keadaan ini adalah menggunakan org.apache.commons.codec.binary.Hexyang memiliki API yang berguna untuk mengubah antara Stringy hex dan biner. Sebagai contoh:

  1. Hex.decodeHex(char[] data)yang melempar DecoderExceptionjika ada karakter non-hex dalam larik, atau jika ada jumlah karakter ganjil.

  2. Hex.encodeHex(byte[] data)adalah pasangan dari metode decode di atas, dan mengeluarkan file char[].

  3. Hex.encodeHexString(byte[] data)yang mengubah kembali dari bytearray menjadi a String.

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

rbrtl
sumber
1

Anda dapat menggunakan fungsi utilitas ini:

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

Tidak seperti varian Denys Séguret dan stefan.schwetschke, ini memungkinkan penyisipan simbol pemisah (spasi, tab, dll.) Ke dalam string input, membuatnya lebih mudah dibaca.

Contoh penggunaan:

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
sumber
-2
private static final int[] CDRIVES = new int[] {0xe0, 0xf4, ...};

dan setelah akses dikonversi ke byte.

Frankie
sumber