Un moyen facile de concaténer des tableaux de deux octets


249

Quelle est la méthode la plus simple pour concaténer deux bytetableaux?

Dire,

byte a[];
byte b[];

Comment concaténer deux bytebaies et les stocker dans une autre bytebaie?


3
Remarque s'il vous plaît que Apache Commons, goyave de Google, System.arrayCopy, ByteBufferet - pas efficace mais lisible - ByteArrayOutputStreamont tous été couverts. Nous avons plus de 7 dupes des réponses données ici. Merci de ne plus poster de dupes.
Maarten Bodewes

Réponses:


317

Le plus simple:

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

La façon la plus élégante de le faire est d'utiliser a ByteArrayOutputStream.

byte a[];
byte b[];

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

byte c[] = outputStream.toByteArray( );

61
@vipw La raison pour laquelle cela est élégant est que si / quand vous souhaitez concaténer un troisième tableau plus tard, vous ajoutez simplement la ligne outputStream.write( c );- vous n'avez pas besoin de revenir en arrière et de modifier la ligne où vous créez le tableau d'octets de résultat. De plus, la réorganisation des tableaux est simple, contrairement à l'utilisation de la méthode arraycopy.
Wayne Uroda

2
De plus, cela est beaucoup plus facile lorsque vous travaillez avec plus de 2 tableaux d'octets.
gardarh

3
Le fait de gaspiller le processeur et la mémoire dépend de la fréquence à laquelle vous effectuez l'opération. Si c'est un milliard de fois par seconde - bien sûr, optimisez-le. Sinon, la lisibilité et la maintenabilité pourraient être les considérations gagnantes.
vikingsteve

5
Si la consommation de mémoire et / ou les performances sont un problème, assurez-vous de l'utiliser a.length + b.lengthcomme argument pour le ByteArrayOutputStreamconstructeur. Notez que cette méthode copiera toujours tous les octets dans un nouveau tableau auquel les affecter c[]! Considérez la ByteBufferméthode comme un concurrent proche, qui ne perd pas de mémoire.
Maarten Bodewes

Je ne peux pas vraiment donner un coup de pouce parce que ce n'est qu'un extrait de code. Il n'y a aucune explication des pièces sous-jacentes ici, qui est la partie qui m'importe (et je pense que la plupart des gens le feraient). Je serais ravi de donner un coup de pouce s'il y avait une comparaison des performances entre System # arrayCopy (Object, int, Object, int, int) et ByteArrayOutputStream # put (byte []), et de préciser quel scénario est le meilleur pour les deux options. Cela étant dit, la réponse devrait également inclure arrayCopy puisque c'est une autre solution.
searchengine27

66

Voici une solution agréable en utilisant goyave de com.google.common.primitives.Bytes:

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

La grande chose à propos de cette méthode est qu'elle a une signature varargs:

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

ce qui signifie que vous pouvez concaténer un nombre arbitraire de tableaux dans un seul appel de méthode.


30

Une autre possibilité utilise java.nio.ByteBuffer.

Quelque chose comme

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

Notez que le tableau doit être correctement dimensionné pour commencer, de sorte que la ligne d'allocation est requise (comme array()renvoie simplement le tableau de support, sans tenir compte du décalage, de la position ou de la limite).


3
@click_whir Désolé mec, mais ReadTheDocs. ByteBuffer.allocate(int)est une méthode statique qui renvoie une java.nio.HeapByteBuffersous-classe instanciée de ByteBuffer. Les méthodes .put()et .compact()- et tout autre caractère abstrait - sont prises en charge.
kalefranz

@kalefranz compact()Ligne supprimée car elle est incorrecte.
Maarten Bodewes

1
Faites attention à utiliser la méthode array () de ByteBuffer - à moins que vous ne sachiez absolument ce que vous faites et que la maintenabilité ne soit pas un problème, rien ne garantit que la position zéro dans le bytebuffer correspond toujours à l'index 0 du tableau d'octets. Voyez ici . Je résous ce problème en émettant bb.flip(); bb.get(result);à la place de la byte[] result = bb.array();ligne.
DarqueSandu

1
@DarqueSandu Bien que ce soit un bon conseil en général , une lecture attentive de la allocateméthode révèle ce qui suit: "La position du nouveau tampon sera zéro, sa limite sera sa capacité, sa marque sera indéfinie et chacun de ses éléments sera initialisé à zéro . Il aura un tableau de support et son décalage de tableau sera nul. " Donc , pour ce particulier morceau de code, où ByteBufferest affecté en interne, ce n'est pas un problème.
Maarten Bodewes

13

Une autre façon est d'utiliser une fonction utilitaire (vous pouvez en faire une méthode statique d'une classe utilitaire générique si vous le souhaitez):

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

Invoquez ainsi:

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

Il fonctionnera également pour concaténer 3, 4, 5 tableaux, etc.

Le faire de cette façon vous donne l'avantage d'un code de tableau rapide qui est également très facile à lire et à entretenir.


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

Même réponse que celle acceptée et désolée, 5 minutes de retard.
Maarten Bodewes

11

Si vous préférez ByteBuffercomme @kalefranz, il y a toujours la possibilité de concaténer deux byte[](voire plus) sur une même ligne, comme ceci:

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

Même réponse que celle-ci mais avec plus d'un an de retard. Utilise le chaînage de méthodes, mais cela serait mieux mis dans la réponse existante.
Maarten Bodewes

11

Vous pouvez utiliser des bibliothèques tierces pour Clean Code comme Apache Commons Lang et l'utiliser comme:

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

1
J'ai essayé ArrayUtils.addAll(a, b)et byte[] c = Bytes.concat(a, b), mais ce dernier est plus rapide.
Carlos Andrés García

Peut être. Je ne connais pas la bibliothèque Guava donc si c'est le cas, il vaut mieux l'utiliser. L'avez-vous vérifié pour les très grands tableaux?
Tomasz Przybylski

1
Lorsque j'ai fait le test, le tableau Firts mesurait 68 éléments et le deuxième 8790688.
Carlos Andrés García

5

Pour deux ou plusieurs tableaux, cette méthode utilitaire simple et propre peut être utilisée:

/**
 * 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
Cela gaspille de la mémoire. La méthode serait OK pour deux petits tableaux, mais elle taxera certainement le garbage collector pour plus de tableaux.
Maarten Bodewes

1

Fusionner deux tableaux d'octets PDF

Si vous fusionnez deux tableaux d'octets contenant du PDF, cette logique ne fonctionnera pas. Nous devons utiliser un outil tiers comme PDFbox d'Apache:

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

un peu hors sujet de cette question, mais c'est exactement ce que je cherchais.
amos

1

Si vous ne voulez pas jouer avec la taille des tableaux, utilisez simplement la magie de la concaténation de chaînes:

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

Ou définissez quelque part dans votre code

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

et utilise

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

Bien entendu, cela fonctionne également avec plus de deux concaténations de chaînes à l'aide de l' +opérateur d'addition.


Les deux "l1"et ISO_8859_1indiquent le jeu de caractères Latin occidental 1 qui code chaque caractère sous la forme d'un octet unique. Comme aucune traduction multi-octets n'est effectuée, les caractères de la chaîne auront les mêmes valeurs que les octets (sauf qu'ils seront toujours interprétés comme des valeurs positives, car charnon signés). Au moins pour le runtime fourni par Oracle, tout octet sera donc correctement «décodé» puis «encodé» à nouveau.

Attention, les chaînes étendent considérablement le tableau d'octets, nécessitant de la mémoire supplémentaire. Les cordes peuvent également être internées et ne seront donc pas faciles à retirer. Les chaînes sont également immuables, de sorte que les valeurs qu'elles contiennent ne peuvent pas être détruites. Vous ne devez donc pas concaténer des tableaux sensibles de cette façon, ni utiliser cette méthode pour des tableaux d'octets plus grands. Il serait également nécessaire de donner une indication claire de ce que vous faites, car cette méthode de concaténation de tableau n'est pas une solution courante.


@MaartenBodewes Si vous n'êtes pas sûr de "l1" (qui est juste un alias pour ISO 8859-1), n'utilisez pas le mot "certainement". Quelle valeur d'octet particulière sera effacée? En ce qui concerne l'utilisation de la mémoire, la question portait sur la manière simple de concaténer des tableaux à deux octets, et non sur la plus efficace en mémoire.
John McClane

1
J'ai mis des avertissements et fait des tests. Pour Latin 1 et le moteur d'exécution fourni par Oracle (11), cela semble fonctionner. J'ai donc fourni des informations supplémentaires et supprimé mon commentaire et mon vote négatif. J'espère que cela vous convient, sinon veuillez revenir en arrière.
Maarten Bodewes

0

C'est ma façon de le faire!

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

Caractéristiques :

  • Utilisez varargs ( ...) pour être appelé avec n'importe quel nombre d'octets [].
  • Utilisation System.arraycopy()implémentée avec du code natif spécifique à la machine, pour garantir un fonctionnement à grande vitesse.
  • Créez un nouvel octet [] avec la taille exacte qui en a besoin.
  • Allouez un peu moins de intvariables en réutilisant les variables iet len.
  • Comparaison plus rapide avec les constantes.

Gardez à l'esprit :

La meilleure façon de le faire est de copier le code @Jonathan . Le problème vient des tableaux de variables natifs, car Java crée de nouvelles variables lorsque ce type de données est transmis à une autre fonction.


1
Non, c'est la façon de faire de Wayne , vous avez 5 ans de retard.
Maarten Bodewes du

@MaartenBodewes Grâce à vous, j'utilise votre commentaire pour exercer le codage aujourd'hui, c'est maintenant plus différent et avec de meilleures performances.
Daniel De León

1
Je ne suis pas sûr que cela importera trop, car la taille des tableaux ne change pas non plus lors de l'exécution, mais elle est maintenant différente au moins de l'autre solution.
Maarten Bodewes
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.