İki bayt diziyi birleştirmenin kolay yolu


249

İki bytediziyi birleştirmenin kolay yolu nedir ?

Söyle,

byte a[];
byte b[];

İki bytediziyi nasıl birleştiririm ve başka bir bytedizide nasıl depolayabilirim ?


3
Not lütfen Apache Commons Google'ın Guava, o System.arrayCopy, ByteBufferve - bu yüzden verimli ama okunabilir değil - ByteArrayOutputStreamtüm kaplanmıştır. Burada verilen cevapların 7'den fazla kopyası var. Lütfen daha fazla kopya göndermeyin.
Maarten Bodewes

Yanıtlar:


317

En açık:

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

377

Bunu yapmanın en zarif yolu a ByteArrayOutputStream.

byte a[];
byte b[];

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

byte c[] = outputStream.toByteArray( );

61
@vipw Bunun zarif olmasının nedeni, üçüncü bir diziyi daha sonra birleştirmek istediğinizde / olduğunda, yalnızca satırı eklemenizdir outputStream.write( c );- geri dönüp sonuç bayt dizisini oluşturduğunuz satırı düzenlemenize gerek yoktur. Ayrıca, dizikopi yönteminden farklı olarak dizileri yeniden sıralamak basittir.
Wayne Uroda

2
Ek olarak, sadece 2 baytlık dizilerle çalışırken bu çok daha kolaydır.
gardarh

3
İşlemcinin ve belleğin boşa harcanıp harcanmadığı, işlemi ne sıklıkta yaptığınıza bağlıdır. Saniyede milyar kez ise - kesin, optimize edin. Aksi takdirde, okunabilirlik ve sürdürülebilirlik kazanan hususlar olabilir.
vikingsteve

5
Bellek tüketimi ve / veya performans önemliyse, yapıcı a.length + b.lengthiçin argüman olarak kullandığınızdan emin olun ByteArrayOutputStream. Bu yöntemin yine de atamak için tüm baytları yeni bir diziye kopyalayacağını unutmayın c[]! ByteBufferYöntemi, belleği boşa harcamayan yakın bir rakip olarak düşünün .
Maarten Bodewes

Bu sadece bir kod pasajı olduğundan gerçekten bir başparmak vazgeçemiyorum. Burada altta yatan parçaların hiçbir açıklaması yok, bu benim umursadığım kısım (ve çoğu insanın yapacağını düşünüyorum). System # arrayCopy (Nesne, int, Nesne, int, int) ve ByteArrayOutputStream # put (bayt []) arasında bir performans karşılaştırması olsaydı ve her iki seçenek için de en iyi senaryo ayrıntılı olursa, bu bir başparmak vazgeçmek istiyorum. Ayrıca, başka bir çözüm olduğu için cevap diziCopy de içermelidir.
searchengine27

66

İşte kullanarak güzel bir çözüm Guava 'ler com.google.common.primitives.Bytes:

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

Bu yöntemle ilgili en iyi şey, varargs imzası olmasıdır:

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

başka bir deyişle, tek bir yöntem çağrısında rastgele sayıda diziyi birleştirebilirsiniz.


30

Başka bir olasılık kullanmaktır java.nio.ByteBuffer.

Gibi bir şey

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

Dizinin başlayabilmesi için uygun şekilde boyutlandırılması gerektiğine dikkat edin, bu nedenle ayırma satırı gereklidir ( array()sadece ofset, konum veya sınır dikkate alınmadan destek dizisini döndürdüğü için).


3
@click_whir Üzgünüm ama ReadTheDocs. ByteBuffer.allocate(int)somutlaştırılmış java.nio.HeapByteBuffer, alt sınıfını döndüren statik bir yöntemdir ByteBuffer. .put()Ve .compact()yöntemler - ve diğer soyut-lık - halledilir.
14:14, kalefranz

@kalefranz compact()Yanlış olduğu için hat kaldırıldı .
Maarten Bodewes

1
ByteBuffer'ın array () yöntemini kullanmaya dikkat edin - ne yaptığınızı kesinlikle bilmediğiniz ve sürdürülebilirliğin bir sorun olmadığı sürece, bytebuffer'daki sıfırıncı konumun her zaman bayt dizisinin 0 dizinine karşılık geldiğine dair bir garanti yoktur. Buraya bakın . Bunu hat bb.flip(); bb.get(result);yerine çıkararak çözüyorum byte[] result = bb.array();.
DarqueSandu

1
@DarqueSandu Genel olarak iyi bir tavsiye olmasına rağmen , allocateyöntemin dikkatli bir şekilde okunması aşağıdakileri ortaya çıkarır: "Yeni tamponun konumu sıfır olacak, sınırı kapasitesi olacak, işareti tanımlanmayacak ve öğelerinin her biri sıfırlanacak Bir yedekleme dizisine sahip olacak ve dizi ofseti sıfır olacaktır. " Yani bunun için belirli kod parçası, ByteBufferdahili olarak tahsis edilir, bu bir sorun değil.
Maarten Bodewes

13

Başka bir yol bir yardımcı program işlevini kullanmaktır (isterseniz bunu genel bir yardımcı sınıfın statik bir yöntemi yapabilirsiniz):

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

Şöyle çağır:

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

Ayrıca 3, 4, 5 dizileri birleştirmek için de çalışır.

Bu şekilde yapmak, okunması ve bakımı çok kolay olan hızlı dizi kod avantajı sağlar.


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

Kabul edilenle aynı cevap ve üzgünüm, 5 dakika geç.
Maarten Bodewes

11

ByteBuffer@Kalefranz'ı tercih ederseniz, her zaman iki byte[](veya daha fazla) bir satırda birleştirme olasılığı vardır , örneğin:

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

Aynı cevabı bu bir ama geç 1 yıldan daha uzun. Yöntem zincirleme kullanır, ancak mevcut cevaba daha iyi konabilir.
Maarten Bodewes

11

Apache Commons Lang gibi Temiz Kod için üçüncü taraf kitaplıklarını kullanabilir ve aşağıdaki gibi kullanabilirsiniz:

byte[] bytes = ArrayUtils.addAll(a, b);

1
Denedim ArrayUtils.addAll(a, b)ve byte[] c = Bytes.concat(a, b)ikincisi daha hızlı.
Carlos Andrés García

Olabilir. Guava kütüphanesini bilmiyorum, öyleyse kullanmak daha iyidir. Çok büyük diziler için kontrol ettiniz mi?
Tomasz Przybylski

1
Testi yaptığımda, Firts dizisi 68 eleman uzunluğunda y ikinci 8790688 uzunluğundaydı.
Carlos Andrés García

5

İki veya birden çok dizi için, bu basit ve temiz yardımcı program yöntemi kullanılabilir:

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

1
Bu hafızayı boşa harcar. Yöntem, iki küçük dizi için uygun olacaktır, ancak kesinlikle daha fazla dizi için çöp toplayıcısını vergilendirecektir.
Maarten Bodewes

1

İki PDF bayt dizisini birleştir

PDF içeren iki bayt dizisini birleştiriyorsanız, bu mantık çalışmaz. Apache'den PDFbox gibi üçüncü taraf bir araç kullanmamız gerekiyor:

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
mergePdf.addSource(new ByteArrayInputStream(a));
mergePdf.addSource(new ByteArrayInputStream(b));
mergePdf.setDestinationStream(byteArrayOutputStream);
mergePdf.mergeDocuments();
c = byteArrayOutputStream.toByteArray();

Bu konuya biraz konu dışı, ama tam olarak aradığım şey bu.
amos

1

Dizilerin boyutlarıyla uğraşmak istemiyorsanız, dize birleştirme sihrini kullanın:

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

Veya kodunuzda bir yer tanımlayın

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

ve kullan

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

Bu, elbette, +toplama operatörünü kullanarak ikiden fazla dize birleştirmesiyle de çalışır .


Her ikisi de "l1"ve ISO_8859_1her karakteri tek bir bayt olarak kodlayan Batı Latin 1 karakter kümesini gösterir. Çok baytlı çeviriler yapılmadığından, dizedeki karakterler baytlarla aynı değerlere sahip olur (yalnızca charimzasız olduğu gibi her zaman pozitif değerler olarak yorumlanırlar ). En azından Oracle tarafından sağlanan çalışma zamanı için, herhangi bir bayt doğru şekilde "kod çözülecek" ve sonra tekrar "kodlanacaktır".

Dizelerin bayt dizisini ek bellek gerektirerek önemli ölçüde genişlettiğine dikkat edin. Teller de stajyer olabilir ve bu nedenle kolayca çıkartılamaz. Dizeler de değişmezdir, bu nedenle içindeki değerler yok edilemez. Bu nedenle, hassas dizileri bu şekilde birleştirmemeli veya bu yöntemi daha büyük bayt dizileri için kullanmamalısınız. Bu dizi birleştirme yöntemi yaygın bir çözüm olmadığından, ne yaptığınıza dair net bir gösterge vermek de gerekecektir.


@MaartenBodewes "l1" (ISO 8859-1 için bir takma addır) hakkında emin değilseniz, "kesinlikle" sözcüğünü kullanmayın. Hangi belirli bayt değeri silinecek? Bellek kullanımına gelince, soru, iki bayt diziyi birleştirmenin kolay bir yoluydu, çoğu bellek verimli olanı değil.
John McClane

1
Bazı uyarılar yaptım ve bazı testler yaptım. Latin 1 ve Oracle tarafından sağlanan çalışma zamanı (11) için bu işe yarıyor gibi görünüyor. Bu yüzden ekstra bilgi sağladım ve yorum ve downvote kaldırıldı. Umarım bu sizin için uygun, aksi takdirde lütfen geri dönün.
Maarten Bodewes

0

Bunu yapmanın yolu bu!

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

Özellikler :

  • İstediğiniz ...sayıda bayt [] ile çağrılmak için varargs ( ) kullanın .
  • Kullan System.arraycopy()yüksek hızda çalışmasını sağlamak için, bu makine Belirli yerel koduyla uygulanmaktadır.
  • Tam olarak ihtiyaç duyulan boyutta yeni bir bayt [] oluşturun.
  • Ve değişkenlerini intyeniden kullanarak daha az değişken tahsis edin .ilen
  • Sabitler ile daha hızlı karşılaştırma.

Unutmayın :

Bunu yapmanın en iyi yolu @Jonathan kodunu kopyalamaktır . Sorun, yerel değişken dizilerinden kaynaklanır, çünkü Java, bu veri türü başka bir işleve geçirildiğinde yeni değişkenler oluşturur.


1
Hayır, Wayne'in bunu yapmanın yolu , 5 yıl geç kaldın.
Maarten Bodewes

@MaartenBodewes Teşekkür ederim, yorumunuzu bugün kodlama yapmak için kullanıyorum, şimdi daha farklı ve daha iyi performansla.
Daniel De León

1
Dizi boyutlarının çalışma zamanında da değişmediğini görerek çok fazla önemli olacağından emin değilim, ama şimdi en azından diğer çözümden farklı.
Maarten Bodewes
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.