Jak łatwo połączyć dwie byte
tablice?
Mówić,
byte a[];
byte b[];
Jak połączyć dwie byte
tablice i przechowywać je w innej byte
tablicy?
Jak łatwo połączyć dwie byte
tablice?
Mówić,
byte a[];
byte b[];
Jak połączyć dwie byte
tablice i przechowywać je w innej byte
tablicy?
Odpowiedzi:
Najbardziej eleganckim sposobem na to jest użycie ByteArrayOutputStream
.
byte a[];
byte b[];
ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
outputStream.write( a );
outputStream.write( b );
byte c[] = outputStream.toByteArray( );
outputStream.write( c );
- nie musisz cofać się i edytować linii, w której utworzono wynikową tablicę bajtów. Również zmiana kolejności tablic jest prosta, w przeciwieństwie do metody arraycopy.
a.length + b.length
argumentu dla ByteArrayOutputStream
konstruktora. Zauważ, że ta metoda nadal skopiuje wszystkie bajty do nowej tablicy, aby ją przypisać c[]
! Rozważ ByteBuffer
metodę bliską rywalkę, która nie marnuje pamięci.
Oto rozwiązanie ładny użyciu Guava „s com.google.common.primitives.Bytes
:
byte[] c = Bytes.concat(a, b);
Wspaniałą rzeczą w tej metodzie jest to, że ma podpis varargs:
public static byte[] concat(byte[]... arrays)
co oznacza, że możesz połączyć dowolną liczbę tablic w jednym wywołaniu metody.
Inną możliwością jest użycie java.nio.ByteBuffer
.
Coś jak
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();
Zauważ, że tablica musi być odpowiednio dobrana na początek, więc wymagana jest linia alokacji (ponieważ array()
po prostu zwraca tablicę bazową, bez uwzględnienia przesunięcia, położenia lub ograniczenia).
ByteBuffer.allocate(int)
jest metodą statyczną, która zwraca instancję java.nio.HeapByteBuffer
, podklasę ByteBuffer
. Zajmuje się metodami .put()
i .compact()
- i każdą inną abstrakcyjnością.
compact()
linię, ponieważ jest niepoprawna.
bb.flip(); bb.get(result);
zamiast byte[] result = bb.array();
wiersza.
allocate
metody ujawnia następujące informacje: „Pozycja nowego bufora będzie wynosić zero, jego limitem będzie pojemność, jego znak będzie niezdefiniowany, a każdy jego element zostanie zainicjowany na zero . Będzie miał tablicę podkładową, a przesunięcie tablicy będzie wynosić zero. Dlatego w przypadku tego konkretnego fragmentu kodu, w którym ByteBuffer
jest on przydzielany wewnętrznie, nie stanowi to problemu.
Innym sposobem jest użycie funkcji narzędzia (jeśli chcesz, możesz to uczynić statyczną metodą ogólnej klasy narzędzi):
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;
}
Wywołaj tak:
byte[] a;
byte[] b;
byte[] result = concat(a, b);
Będzie również działał dla łączenia 3, 4, 5 tablic itp.
Robiąc to w ten sposób, zyskujesz przewagę szybkiego kodu arraycopy, który jest również bardzo łatwy do odczytania i utrzymania.
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);
Jeśli wolisz ByteBuffer
@kalefranz, zawsze istnieje możliwość połączenia dwóch byte[]
(lub nawet więcej) w jednym wierszu, tak jak to:
byte[] c = ByteBuffer.allocate(a.length+b.length).put(a).put(b).array();
Możesz używać bibliotek stron trzecich do czyszczenia kodu, takich jak Apache Commons Lang i używać go w następujący sposób:
byte[] bytes = ArrayUtils.addAll(a, b);
ArrayUtils.addAll(a, b)
i byte[] c = Bytes.concat(a, b)
, ale ten drugi jest szybszy.
W przypadku dwóch lub wielu tablic można zastosować tę prostą i czystą metodę narzędzia:
/**
* 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();
}
Jeśli scalasz dwie tablice bajtów zawierające PDF, ta logika nie będzie działać. Musimy użyć narzędzia innej firmy, takiego jak PDFbox firmy Apache:
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
mergePdf.addSource(new ByteArrayInputStream(a));
mergePdf.addSource(new ByteArrayInputStream(b));
mergePdf.setDestinationStream(byteArrayOutputStream);
mergePdf.mergeDocuments();
c = byteArrayOutputStream.toByteArray();
Jeśli nie chcesz zadzierać z rozmiarami tablic, po prostu użyj magii łączenia łańcuchów:
byte[] c = (new String(a, "l1") + new String(b, "l1")).getBytes("l1");
Lub zdefiniuj gdzieś w swoim kodzie
// concatenation charset
static final java.nio.charset.Charset cch = java.nio.charset.StandardCharsets.ISO_8859_1;
I użyć
byte[] c = (new String(a, cch) + new String(b, cch)).getBytes(cch);
To oczywiście działa również z więcej niż dwoma łączeniami łańcuchowymi za pomocą +
operatora dodawania.
Oba "l1"
i ISO_8859_1
wskazują zestaw znaków Western Latin 1, który koduje każdy znak jako pojedynczy bajt. Ponieważ nie są wykonywane tłumaczenia wielobajtowe, znaki w ciągu będą miały takie same wartości jak bajty (z tym wyjątkiem, że zawsze będą interpretowane jako wartości dodatnie, ponieważ nie char
są podpisane). Przynajmniej w przypadku środowiska wykonawczego dostarczonego przez Oracle każdy bajt zostanie zatem poprawnie „zdekodowany”, a następnie „ponownie zakodowany”.
Uwaga: ciągi znacznie rozszerzają tablicę bajtów, co wymaga dodatkowej pamięci. Łańcuchy mogą być również internowane i dlatego nie będą łatwe do usunięcia. Ciągi są również niezmienne, więc wartości wewnątrz nich nie można zniszczyć. Dlatego nie powinieneś łączyć wrażliwych tablic w ten sposób, ani nie powinieneś używać tej metody dla tablic o większych bajtach. Wymagane byłoby również wyraźne wskazanie tego, co robisz, ponieważ ta metoda konkatenacji macierzy nie jest powszechnym rozwiązaniem.
To jest mój sposób, aby to zrobić!
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;
}
Funkcje :
...
), aby wywołać dowolną liczbę bajtów [].System.arraycopy()
które jest zaimplementowane z natywnym kodem specyficznym dla maszyny, aby zapewnić szybkie działanie.int
zmiennych, ponownie wykorzystując zmienne i
i len
.Pamiętaj :
Lepszym sposobem na to jest skopiowanie kodu @Jonathan . Problem pochodzi z rodzimych tablic zmiennych, ponieważ Java tworzy nowe zmienne, gdy ten typ danych jest przekazywany do innej funkcji.
System.arrayCopy
,ByteBuffer
a część - nie tak skuteczne, ale czytelny -ByteArrayOutputStream
wszystkie zostały pokryte. Mamy ponad 7 duplikatów podanych tutaj odpowiedzi. Nie publikuj więcej duplikatów.