2 바이트 배열을 연결하는 쉬운 방법


249

두 가지를 연결하는 쉬운 방법은 무엇입니까 byte 배열 ?

말하다,

byte a[];
byte b[];

byte배열을 연결 하여 다른 byte배열에 저장하려면 어떻게합니까 ?


3
아파치 커먼즈, 구글의 구아바 (Guava System.arrayCopy) ByteBuffer및 그다지 효율적이지 않고 읽을 수 ByteArrayOutputStream있는 것들이 모두 다루어 져 있다. 우리는 여기에 주어진 답을 7 회 이상 습득했습니다. 더 이상 속임수를 게시하지 마십시오.
Maarten Bodewes

답변:


317

가장 간단합니다 :

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

이 작업을 수행하는 가장 우아한 방법은입니다 ByteArrayOutputStream.

byte a[];
byte b[];

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

byte c[] = outputStream.toByteArray( );

61
@vipw 이것이 우아한 이유는 나중에 세 번째 배열을 연결하려는 경우 단순히 행을 추가 outputStream.write( c );하기 때문입니다. 결과 바이트 배열을 만드는 위치로 돌아가서 편집 할 필요가 없습니다. 또한 arraycopy 메서드를 사용하는 것과 달리 배열의 순서를 바꾸는 것은 간단합니다.
웨인 우로 다

2
또한 2 바이트 이상의 어레이로 작업 할 때 훨씬 쉽습니다.
gardarh

3
CPU와 메모리를 낭비하는지 여부는 작업을 얼마나 자주 수행하는지에 따라 다릅니다. 초당 10 억 번이면 최적화하십시오. 그렇지 않으면 가독성과 유지 관리 성이 중요한 고려 사항이 될 수 있습니다.
vikingsteve

5
메모리 소비 및 / 또는 성능이 중요한 a.length + b.length경우 ByteArrayOutputStream생성자에 대한 인수 로 사용하십시오 . 이 메소드는 여전히 모든 바이트를 새로운 배열에 복사하여 할당합니다 c[]! 이 ByteBuffer방법은 메모리를 낭비하지 않는 가까운 경쟁자를 고려하십시오 .
Maarten Bodewes

코드 스 니펫 일 뿐이므로 실제로 엄지 손가락을 줄 수는 없습니다. 여기에 기본 조각에 대한 설명이 없습니다.이 부분은 내가 관심있는 부분이며 대부분의 사람들이 생각합니다. System # arrayCopy (Object, int, Object, int, int)와 ByteArrayOutputStream # put (byte []) 사이의 성능 비교가 있고 두 옵션에 가장 적합한 시나리오에 대해 자세히 설명하면 기꺼이 이것을 승인합니다. 또한, 그 대답은 또 다른 솔루션이므로 arrayCopy도 포함해야합니다.
searchengine27

66

여기에 사용하여 좋은 솔루션입니다 구아바 '들 com.google.common.primitives.Bytes:

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

이 방법의 가장 큰 장점은 varargs 서명이 있다는 것입니다.

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

즉, 단일 메소드 호출에서 임의의 수의 배열을 연결할 수 있습니다.


30

또 다른 가능성은을 사용하는 것 java.nio.ByteBuffer입니다.

같은 것

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

배열은 시작하기에 적절한 크기 여야하므로 할당 라인이 필요합니다 ( array()오프셋, 위치 또는 제한을 고려하지 않고 단순히 배킹 배열을 반환하기 만하면 됨).


3
@click_whir 죄송 합니다만 ReadTheDocs입니다. ByteBuffer.allocate(int)의 인스턴스 java.nio.HeapByteBuffer인 인스턴스화 된을 반환하는 정적 메서드 입니다 ByteBuffer. .put().compact()방법 - 그리고 다른 추상 다움 - 알아서한다.
kalefranz

@kalefranz compact()잘못된 행을 제거 했습니다.
Maarten Bodewes

1
ByteBuffer의 array () 메소드 사용에주의하십시오. 수행중인 작업을 절대적으로 알지 못하고 유지 관리 성이 문제가되지 않는 한 바이트 버퍼의 0 번째 위치가 항상 바이트 배열의 인덱스 0에 해당한다는 보장은 없습니다. 여기를 참조 하십시오 . 나는 줄 bb.flip(); bb.get(result);대신 에 발행하여 이것을 해결합니다 byte[] result = bb.array();.
DarqueSandu

1
@DarqueSandu 일반적으로 좋은 조언이지만이 allocate방법을 주의 깊게 읽으면 다음과 같은 결과가 나타납니다. "새로운 버퍼의 위치는 0이되고, 한계는 용량이되고, 표시는 정의되지 않으며, 각 요소는 0으로 초기화됩니다. "배열 배열을 갖게되고 배열 오프셋은 0이됩니다." 따라서 내부적으로 할당 되는 이 특정 코드 ByteBuffer는 문제가되지 않습니다.
Maarten Bodewes

13

다른 방법은 유틸리티 함수를 사용하는 것입니다 (원하는 경우 일반 유틸리티 클래스의 정적 메소드로 만들 수 있음).

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

다음과 같이 호출하십시오.

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

3, 4, 5 배열 등을 연결하는 데에도 사용됩니다.

이 방법을 사용하면 읽기 및 유지 관리가 매우 쉬운 빠른 어레이 복사 코드의 이점이 있습니다.


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

5 분 늦게 접수 된 답변과 동일한 답변 입니다.
Maarten Bodewes

11

ByteBuffer@kalefranz와 같은 것을 선호한다면 항상 다음 byte[]과 같이 한 줄에 두 개 (또는 그 이상) 를 연결할 가능성 이 있습니다.

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

동일 답 이 하나 있지만, 후반 1 년 이상. 메소드 체인을 사용하지만 기존 답변에 더 적합합니다.
Maarten Bodewes

11

Apache Commons Lang과 같은 Clean Code에 타사 라이브러리를 사용하고 다음과 같이 사용할 수 있습니다.

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

1
나는 시도 ArrayUtils.addAll(a, b)하고 byte[] c = Bytes.concat(a, b)있지만, 후자는 빠릅니다.
Carlos Andrés García

아마도. 구아바 라이브러리를 모르므로 사용하는 것이 좋습니다. 매우 큰 배열을 확인 했습니까?
Tomasz Przybylski

1
테스트를 수행했을 때 Firts 배열은 68 요소 길이와 두 번째 8790688 길이였습니다.
카를로스 안드레스 가르시아

5

두 개 또는 여러 개의 어레이에 대해이 간단하고 깔끔한 유틸리티 방법을 사용할 수 있습니다.

/**
 * 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
메모리가 낭비됩니다. 이 방법은 두 개의 작은 배열에 대해서는 괜찮지 만 더 많은 배열에 대해 가비지 수집기에 세금을 부과합니다.
Maarten Bodewes

1

두 개의 PDF 바이트 배열 병합

PDF가 포함 된 2 바이트 배열을 병합하는 경우이 논리가 작동하지 않습니다. Apache의 PDFbox와 같은 타사 도구를 사용해야합니다.

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

이 질문에 대한 약간의 주제이지만 정확히 내가 찾던 것입니다.
amos

1

배열의 크기를 엉망으로 만들고 싶지 않다면 문자열 연결 마법을 사용하십시오.

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

또는 코드 어딘가에 정의하십시오.

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

사용

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

물론 이것은 +더하기 연산자를 사용하여 둘 이상의 문자열 연결에서도 작동합니다 .


둘 다 "l1"ISO_8859_1각 문자를 단일 바이트로 인코딩하는 서부 라틴어 1 문자 세트를 나타냅니다. 멀티 바이트 변환이 수행되지 않으므로 문자열의 문자는 바이트와 동일한 값을 갖습니다 (단, 항상 양의 값으로 해석됨을 제외하고).char 부호없는 ). 최소한 오라클이 제공 한 런타임의 경우 모든 바이트가 올바르게 "디코딩"된 후 다시 "인코딩"됩니다.

문자열은 바이트 배열을 상당히 확장하므로 추가 메모리가 필요합니다. 문자열도 억지로 묶을 수 있으므로 쉽게 제거 할 수 없습니다. 문자열도 변경할 수 없으므로 내부의 값을 삭제할 수 없습니다. 따라서 민감한 배열을 이런 식으로 연결하거나 더 큰 바이트 배열에이 방법을 사용해서는 안됩니다. 이 배열 연결 방법은 일반적인 솔루션이 아니므로 수행중인 작업을 명확하게 표시해야합니다.


@MaartenBodewes ISO 8859-1의 별명 인 "l1"에 대해 잘 모르면 "확실히"라는 단어를 사용하지 마십시오. 어떤 특정 바이트 값이 지워 집니까? 메모리 사용에 관한 문제는 대부분의 메모리 효율적인 것이 아니라 2 바이트 배열을 연결 하는 쉬운 방법에 관한 것입니다.
John McClane

1
경고를 표시하고 테스트를 수행했습니다. 라틴어 1 및 Oracle 제공 런타임 (11)의 경우 작동하는 것 같습니다. 그래서 추가 정보를 제공하고 내 의견과 downvote를 제거했습니다. 나는 그것이 당신을 위해 괜찮기를 바랍니다. 그렇지 않으면 롤백하십시오.
Maarten Bodewes

0

이것이 내 길입니다!

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

특징 :

  • varargs (... )를 하여 원하는 수의 바이트 []로 호출하십시오.
  • 사용하여 System.arraycopy()고속 작동을 보장하기 위해, 그이 기계 특정 네이티브 코드로 구현됩니다.
  • 필요한 정확한 크기로 새 byte []를 작성하십시오.
  • 및 변수 int를 재사용하여 적은 변수를 할당 하십시오.ilen
  • 상수와 더 빠른 비교.

명심하십시오 :

더 좋은 방법은 @Jonathan 코드 를 복사하는 것 입니다. Java는이 데이터 유형이 다른 함수에 전달 될 때 새 변수를 작성하기 때문에 기본 변수 배열에서 발생합니다.


1
아니, 그건 웨인이하는 길 이야 5 년 늦었 어
Maarten Bodewes

@MaartenBodewes 덕분에 오늘 코딩을 연습하기 위해 귀하의 의견을 사용합니다. 이제는 더 다르고 성능이 향상되었습니다.
Daniel De León

1
배열 크기가 런타임에서 변경되지 않는 것을 보는 것이 너무 중요하지는 않지만 적어도 다른 솔루션과는 다릅니다.
Maarten Bodewes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.