ChatGPT解决这个技术问题 Extra ChatGPT

连接两个字节数组的简单方法

连接两个 byte 数组的简单方法是什么?

说,

byte a[];
byte b[];

如何连接两个 byte 数组并将其存储在另一个 byte 数组中?

请注意,Apache Commons、Google 的 Guava、System.arrayCopyByteBuffer 和 - 效率不高但易读的 - ByteArrayOutputStream 都已涵盖。我们在这里给出的答案有超过 7 个重复。请不要再发布任何骗局。

A
AskNilesh

最优雅的方法是使用 ByteArrayOutputStream

byte a[];
byte b[];

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

byte c[] = outputStream.toByteArray( );

@vipw这很优雅的原因是因为如果/当您希望稍后连接第三个数组时,您只需添加行 outputStream.write( c ); - 您不必返回并编辑创建结果字节数组的行.此外,与使用 arraycopy 方法不同,对数组重新排序很简单。
此外,当使用超过 2 个字节的数组时,这要容易得多。
是否浪费cpu和内存取决于您执行操作的频率。如果它是每秒十亿次 - 当然,优化它。否则,可读性和可维护性可能是获胜的考虑因素。
如果内存消耗和/或性能是一个问题,请务必使用 a.length + b.length 作为 ByteArrayOutputStream 构造函数的参数。请注意,此方法仍会将所有字节复制到一个新数组以分配给 c[]!将 ByteBuffer 方法视为一个紧密的竞争者,它不会浪费内存。
我真的不能竖起大拇指,因为这只是一个代码片段。这里没有对底层部分的解释,这是我关心的部分(我想大多数人都会关心)。如果在 System#arrayCopy(Object, int, Object, int, int) 和 ByteArrayOutputStream#put(byte[]) 之间进行性能比较,我会很高兴地对此表示赞赏,并详细说明哪种方案最适合这两个选项。此外,话虽如此,答案还应该包括 arrayCopy 因为这是另一种解决方案。
J
Jonathan

最直接的:

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

像魅力一样工作
Z
Zoltán

这是使用 Guavacom.google.common.primitives.Bytes 的一个很好的解决方案:

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

这个方法的好处是它有一个可变参数签名:

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

这意味着您可以在单个方法调用中连接任意数量的数组。


这是最简单的方法。顺便说一句,如果您使用的是 Groovy,则没有区别。
P
Pavel Repin

另一种可能性是使用 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() 仅返回支持数组,而不考虑偏移量、位置或限制)。


@click_whir 对不起,伙计,但 ReadTheDocs。 ByteBuffer.allocate(int) 是一个静态方法,它返回一个实例化的 java.nio.HeapByteBuffer,它是 ByteBuffer 的子类。 .put().compact() 方法——以及任何其他抽象性——都得到了处理。
@kalefranz 删除了 compact() 行,因为它不正确。
小心使用 ByteBuffer 的 array() 方法——除非你绝对知道你在做什么并且可维护性不是问题,否则不能保证字节缓冲区中的第零位总是对应于字节数组的索引 0。请参阅here。我通过发出 bb.flip(); bb.get(result); 而不是 byte[] result = bb.array(); 行来解决这个问题。
@DarqueSandu 虽然总的来说这是个好建议,但仔细阅读 allocate 方法会发现以下内容:“新缓冲区的位置将为零,其限制将是其容量,其标记将未定义,并且它的每个元素都将被初始化为零。它将有一个支持数组,并且它的数组偏移量将为零。因此,对于这段 特定 代码,其中 ByteBuffer 是在内部分配的,这不是问题。
W
Wayne Uroda

另一种方法是使用实用程序函数(如果您愿意,可以将其设为通用实用程序类的静态方法):

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 个数组等。

这样做可以为您提供快速数组复制代码的优势,该代码也非常易于阅读和维护。


T
Tomasz Przybylski

您可以将第三方库用于清洁代码,例如 Apache Commons Lang,并使用它:

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

我试过 ArrayUtils.addAll(a, b)byte[] c = Bytes.concat(a, b),但后者更快。
也许。我不知道 Guava 库,所以如果是的话,最好使用它。你检查过非常大的数组吗?
当我进行测试时,Firts 数组是 68 个元素长度 y 第二个 8790688 长度。
J
James.Xu
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);

accepted one 的答案相同,抱歉,迟到了 5 分钟。
Z
ZEuS

如果您更喜欢 @kalefranz 之类的 ByteBuffer,则始终可以在一行中连接两个 byte[](甚至更多),如下所示:

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

答案与 this one 相同,但晚了 1 年多。使用方法链接,但最好将其放入现有答案中。
J
Jeroen Meulemeester

对于两个或多个阵列,可以使用这种简单而干净的实用方法:

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

这会浪费内存。该方法适用于两个较小的数组,但它肯定会对更多数组的垃圾收集器征税。
C
Community

合并两个 PDF 字节数组

如果您要合并两个包含 PDF 的字节数组,则此逻辑将不起作用。我们需要使用第三方工具,例如 Apache 的 PDFbox:

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

这个问题有点偏离主题,但正是我想要的。
M
Maarten Bodewes

如果您不想弄乱数组的大小,只需使用字符串连接的魔力:

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 都表示将每个字符编码为单个字节的 Western Latin 1 字符集。由于不执行多字节转换,字符串中的字符将具有与字节相同的值(除了它们将始终被解释为正值,因为 char 是无符号的)。至少对于 Oracle 提供的运行时,任何字节都将因此被正确“解码”,然后再次“编码”。

请注意,字符串确实会周到地扩展字节数组,需要额外的内存。字符串也可能被扣留,因此不容易被移除。字符串也是不可变的,因此其中的值不能被破坏。因此,您不应以这种方式连接敏感数组,也不应将此方法用于较大的字节数组。还需要明确指示您正在做什么,因为这种数组连接方法不是常见的解决方案。


@MaartenBodewes 如果您不确定“l1”(这只是 ISO 8859-1 的别名),请不要使用“肯定”这个词。哪个特定的字节值将被清除?至于内存使用,问题在于连接两个字节数组的简单方法,而不是最节省内存的方法。
我已经提出了一些警告并进行了一些测试。对于拉丁语 1 和 Oracle 提供的运行时 (11),这似乎确实有效。所以我提供了额外的信息并删除了我的评论和反对票。我希望这对你没问题,否则请回滚。
D
Daniel De León

这是我的方法!

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

特征:

使用可变参数 (...) 以任意数量的 byte[] 调用。

使用通过机器特定的本机代码实现的 System.arraycopy(),以确保高速运行。

创建一个具有所需确切大小的新字节 []。

通过重用 i 和 len 变量来分配更少的 int 变量。

更快地与常数进行比较。

记住:

更好的方法是复制 @Jonathan code。问题来自本机变量数组,因为当这种数据类型传递给另一个函数时,Java 会创建新变量。


不,那是 Wayne's way to do it,你迟到了 5 年。
@MaartenBodewes 感谢您,我今天使用您的评论来练习编码,现在更加不同并且性能更好。
我不确定它会不会太重要,因为数组大小在运行时也不会改变,但它现在至少与其他解决方案不同。
m
madx

如果您已经在加载 Guava 库,则可以使用 com.google.common.primitives.Bytes 中的静态方法 concat(byte[]... arrays)

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

以下是“Kevin Bourrillion”的 concat(byte[]... arrays) 方法的独立 source

public static byte[] concat(byte[]... arrays) {
    int length = 0;
    for (byte[] array : arrays) {
        length += array.length;
    }
    byte[] result = new byte[length];
    int pos = 0;
    for (byte[] array : arrays) {
        System.arraycopy(array, 0, result, pos, array.length);
        pos += array.length;
    }
    return result;
}