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.