Cara mudah untuk menggabungkan array dua byte

249

Apa cara mudah untuk menggabungkan dua bytearray?

Mengatakan,

byte a[];
byte b[];

Bagaimana cara menggabungkan dua bytearray dan menyimpannya di bytearray lain ?

androidGuy
sumber
3
Harap dicatat bahwa Apache Commons, Google's Guava System.arrayCopy, ByteBufferdan - tidak begitu efisien tetapi dapat dibaca - ByteArrayOutputStreamsemuanya telah dibahas. Kami memiliki lebih dari 7 dupes jawaban yang diberikan di sini. Tolong jangan memposting dupes lagi.
Maarten Bodewes

Jawaban:

317

Paling mudah:

byte[] c = new byte[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
Jonathan
sumber
377

Cara paling elegan untuk melakukan ini adalah dengan a ByteArrayOutputStream.

byte a[];
byte b[];

ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
outputStream.write( a );
outputStream.write( b );

byte c[] = outputStream.toByteArray( );
Kevin
sumber
61
@ vipw Alasan mengapa ini elegan adalah karena jika / ketika Anda ingin menggabungkan array ketiga nanti, Anda cukup menambahkan baris outputStream.write( c );- Anda tidak harus kembali dan mengedit baris tempat Anda membuat array byte hasil. Juga, memesan ulang array itu sederhana, tidak seperti menggunakan metode arraycopy.
Wayne Uroda
2
Selain itu, ini jauh lebih mudah ketika bekerja dengan lebih dari hanya 2 byte array.
gardarh
3
Apakah itu membuang cpu dan memori tergantung pada seberapa sering Anda melakukan operasi. Jika satu miliar kali per detik - tentu saja, optimalkan. Jika tidak, keterbacaan dan pemeliharaan mungkin menjadi pertimbangan utama.
vikingsteve
5
Jika konsumsi memori dan / atau kinerja menjadi perhatian, pastikan untuk digunakan a.length + b.lengthsebagai argumen untuk ByteArrayOutputStreamkonstruktor. Perhatikan bahwa metode ini masih akan menyalin semua byte ke array baru untuk ditugaskan c[]! Pertimbangkan ByteBuffermetode ini sebagai pesaing dekat, yang tidak menghabiskan memori.
Maarten Bodewes
Saya tidak bisa memberikan ini jempol karena ini hanya cuplikan kode. Tidak ada penjelasan tentang bagian yang mendasarinya di sini, yang merupakan bagian yang saya pedulikan (dan saya pikir kebanyakan orang akan). Saya dengan senang hati akan memberikan acungan jempol jika ada perbandingan kinerja antara System # arrayCopy (Object, int, Object, int, int) dan ByteArrayOutputStream # put (byte []), dan merinci skenario mana yang terbaik untuk kedua opsi. Juga, yang dikatakan, jawabannya juga harus menyertakan arrayCopy karena itu adalah solusi lain.
searchengine27
66

Berikut adalah solusi yang bagus menggunakan Jambu 's com.google.common.primitives.Bytes:

byte[] c = Bytes.concat(a, b);

Hal yang hebat tentang metode ini adalah ia memiliki tanda tangan varargs:

public static byte[] concat(byte[]... arrays)

yang berarti bahwa Anda dapat menggabungkan jumlah array sewenang-wenang dalam satu pemanggilan metode tunggal.

Zoltán
sumber
30

Kemungkinan lain adalah menggunakan java.nio.ByteBuffer.

Sesuatu seperti

ByteBuffer bb = ByteBuffer.allocate(a.length + b.length + c.length);
bb.put(a);
bb.put(b);
bb.put(c);
byte[] result = bb.array();

// or using method chaining:

byte[] result = ByteBuffer
        .allocate(a.length + b.length + c.length)
        .put(a).put(b).put(c)
        .array();

Perhatikan bahwa array harus berukuran tepat untuk memulainya, sehingga garis alokasi diperlukan ( array()hanya mengembalikan array dukungan, tanpa memperhitungkan offset, posisi, atau batas).

kalefranz
sumber
3
@click_whir Maaf, tapi ReadTheDocs. ByteBuffer.allocate(int)adalah metode statis yang mengembalikan instantiated java.nio.HeapByteBuffer, subclass dari ByteBuffer. Metode .put()dan .compact()- dan keabstrakan lainnya - dijaga.
kalefranz
@kalefranz Menghapus compact()baris karena tidak benar.
Maarten Bodewes
1
Berhati-hatilah dalam menggunakan metode ByteBuffer's () - kecuali Anda benar-benar tahu apa yang Anda lakukan dan rawatan tidak menjadi masalah, tidak ada jaminan bahwa posisi nol di bytebuffer selalu sesuai dengan indeks 0 array byte. Lihat di sini . Saya memecahkan masalah ini dengan menerbitkan bb.flip(); bb.get(result);sebagai ganti byte[] result = bb.array();baris.
DarqueSandu
1
@DarqueSandu Meskipun itu saran yang bagus secara umum , pembacaan yang cermat atas allocatemetode ini mengungkapkan hal berikut: "Posisi buffer baru akan nol, batasnya adalah kapasitasnya, tandanya akan tidak ditentukan, dan masing-masing elemennya akan diinisialisasi ke nol Ini akan memiliki array pendukung, dan offset arraynya akan nol. " Jadi untuk ini khusus potongan kode, di mana ByteBufferdialokasikan secara internal, itu tidak masalah.
Maarten Bodewes
13

Cara lain adalah dengan menggunakan fungsi utilitas (Anda bisa menjadikan ini metode statis kelas utilitas generik jika Anda mau):

byte[] concat(byte[]...arrays)
{
    // Determine the length of the result array
    int totalLength = 0;
    for (int i = 0; i < arrays.length; i++)
    {
        totalLength += arrays[i].length;
    }

    // create the result array
    byte[] result = new byte[totalLength];

    // copy the source arrays into the result array
    int currentIndex = 0;
    for (int i = 0; i < arrays.length; i++)
    {
        System.arraycopy(arrays[i], 0, result, currentIndex, arrays[i].length);
        currentIndex += arrays[i].length;
    }

    return result;
}

Ajukan seperti ini:

byte[] a;
byte[] b;
byte[] result = concat(a, b);

Ini juga akan berfungsi untuk menggabungkan 3, 4, 5 array, dll.

Melakukannya dengan cara ini memberi Anda keuntungan dari kode arraycopy cepat yang juga sangat mudah dibaca dan dipelihara.

Wayne Uroda
sumber
11
byte[] result = new byte[a.length + b.length];
// copy a to result
System.arraycopy(a, 0, result, 0, a.length);
// copy b to result
System.arraycopy(b, 0, result, a.length, b.length);
James.Xu
sumber
Jawaban yang sama seperti yang diterima dan maaf, terlambat 5 menit.
Maarten Bodewes
11

Jika Anda lebih suka ByteBufferseperti @kalefranz, selalu ada kemungkinan untuk menggabungkan dua byte[](atau bahkan lebih) dalam satu baris, seperti ini:

byte[] c = ByteBuffer.allocate(a.length+b.length).put(a).put(b).array();
ZEuS
sumber
Jawaban yang sama seperti ini tetapi terlambat lebih dari 1 tahun. Menggunakan metode chaining, tetapi itu akan lebih baik dimasukkan ke dalam jawaban yang ada.
Maarten Bodewes
11

Anda dapat menggunakan perpustakaan pihak ketiga untuk Kode Bersih seperti Apache Commons Lang dan menggunakannya seperti:

byte[] bytes = ArrayUtils.addAll(a, b);
Tomasz Przybylski
sumber
1
Saya mencoba ArrayUtils.addAll(a, b)dan byte[] c = Bytes.concat(a, b), tetapi yang terakhir lebih cepat.
Carlos Andrés García
Mungkin. Saya tidak tahu perpustakaan Guava jadi jika ya, lebih baik menggunakannya. Apakah Anda memeriksa array yang sangat besar?
Tomasz Przybylski
1
Ketika saya melakukan tes, array Firts adalah 68 elemen panjang y panjang 8790688 kedua.
Carlos Andrés García
5

Untuk dua atau beberapa array, metode utilitas sederhana dan bersih ini dapat digunakan:

/**
 * Append the given byte arrays to one big array
 *
 * @param arrays The arrays to append
 * @return The complete array containing the appended data
 */
public static final byte[] append(final byte[]... arrays) {
    final ByteArrayOutputStream out = new ByteArrayOutputStream();
    if (arrays != null) {
        for (final byte[] array : arrays) {
            if (array != null) {
                out.write(array, 0, array.length);
            }
        }
    }
    return out.toByteArray();
}
Jeroen Meulemeester
sumber
1
Ini menghabiskan memori. Metode ini akan OK untuk dua array yang lebih kecil, tetapi tentu akan memungut pajak dari pemulung untuk lebih banyak array.
Maarten Bodewes
1

Gabungkan dua array byte PDF

Jika Anda menggabungkan array dua byte yang berisi PDF, logika ini tidak akan berfungsi. Kita perlu menggunakan alat pihak ketiga seperti PDFbox dari Apache:

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
mergePdf.addSource(new ByteArrayInputStream(a));
mergePdf.addSource(new ByteArrayInputStream(b));
mergePdf.setDestinationStream(byteArrayOutputStream);
mergePdf.mergeDocuments();
c = byteArrayOutputStream.toByteArray();
Bala Vignesh B
sumber
sedikit topik untuk pertanyaan ini, tetapi persis apa yang saya cari.
Amos
1

Jika Anda tidak ingin mengacaukan dengan ukuran array, cukup gunakan keajaiban penggabungan string:

byte[] c = (new String(a, "l1") + new String(b, "l1")).getBytes("l1");

Atau tentukan di suatu tempat dalam kode Anda

// concatenation charset
static final java.nio.charset.Charset cch = java.nio.charset.StandardCharsets.ISO_8859_1;

dan gunakan

byte[] c = (new String(a, cch) + new String(b, cch)).getBytes(cch);

Ini, tentu saja, juga bekerja dengan lebih dari dua rangkaian string menggunakan +operator tambahan.


Keduanya "l1"dan ISO_8859_1menunjukkan set karakter Latin 1 Barat yang mengkodekan setiap karakter sebagai byte tunggal. Karena tidak ada terjemahan multi-byte yang dilakukan, karakter dalam string akan memiliki nilai yang sama dengan byte (kecuali bahwa mereka akan selalu ditafsirkan sebagai nilai positif, seperti yang chartidak ditandatangani). Setidaknya untuk runtime yang disediakan Oracle, byte apa pun karena itu akan benar "diterjemahkan" dan kemudian "dikodekan" lagi.

Berhati-hatilah karena string perlu memperluas array byte secara matang, membutuhkan memori tambahan. String juga dapat diinternir dan karenanya tidak mudah dihilangkan. String juga tidak dapat diubah, sehingga nilai-nilai di dalamnya tidak dapat dihancurkan. Karena itu Anda tidak boleh menggabungkan array sensitif dengan cara ini atau Anda harus menggunakan metode ini untuk array byte yang lebih besar. Memberikan indikasi yang jelas tentang apa yang Anda lakukan juga akan diperlukan, karena metode penggabungan array ini bukanlah solusi yang umum.

John McClane
sumber
@ MaartenBodewes Jika Anda tidak yakin tentang "l1" (yang hanya merupakan alias untuk ISO 8859-1), jangan gunakan kata "tentu". Nilai byte tertentu mana yang akan dihapus? Sedangkan untuk penggunaan memori, pertanyaannya adalah tentang cara mudah untuk menggabungkan array dua byte, bukan tentang sebagian besar memori efisien.
John McClane
1
Saya telah meletakkan beberapa peringatan dan melakukan beberapa pengujian. Untuk Latin 1 dan runtime yang disediakan oleh Oracle (11) ini sepertinya berfungsi. Jadi saya memberikan info tambahan dan menghapus komentar dan downvote saya. Saya harap tidak apa-apa untuk Anda, jika tidak silakan mundur.
Maarten Bodewes
0

Ini cara saya melakukannya!

public static byte[] concatByteArrays(byte[]... inputs) {
    int i = inputs.length - 1, len = 0;
    for (; i >= 0; i--) {
        len += inputs[i].length;
    }
    byte[] r = new byte[len];
    for (i = inputs.length - 1; i >= 0; i--) {
        System.arraycopy(inputs[i], 0, r, len -= inputs[i].length, inputs[i].length);
    }
    return r;
}

Fitur :

  • Gunakan varargs ( ...) untuk dipanggil dengan sejumlah byte [].
  • Gunakan System.arraycopy()yang diterapkan dengan kode asli khusus mesin, untuk memastikan operasi kecepatan tinggi.
  • Buat byte baru [] dengan ukuran tepat yang membutuhkannya.
  • Alokasikan lebih sedikit intvariabel dengan menggunakan kembali variabel idan len.
  • Perbandingan lebih cepat dengan konstanta.

Ingatlah :

Cara yang lebih baik untuk melakukan ini, adalah dengan menyalin kode @ Jonathan . Masalahnya berasal dari array variabel asli, karena Java membuat variabel baru ketika tipe data ini diteruskan ke fungsi lain.

Daniel De León
sumber
1
Tidak, itu cara Wayne untuk melakukannya , Anda terlambat 5 tahun.
Maarten Bodewes
@ MaartenBodewes Terima kasih kepada Anda, saya menggunakan komentar Anda untuk melakukan pengkodean hari ini, sekarang lebih berbeda dan dengan kinerja yang lebih baik.
Daniel De León
1
Saya tidak yakin itu akan terlalu banyak masalah, melihat bahwa ukuran array tidak berubah dalam runtime juga, tetapi sekarang berbeda setidaknya dari solusi lain.
Maarten Bodewes