76 votes

Tableau d'octets de longueur inconnue en java

Je construis un tableau d'octets en Java et je ne sais pas quelle sera la longueur du tableau.

J'ai besoin d'un outil comme le StringBuffer de Java que vous pouvez juste appeler .append(byte b) ou .append(byte[] buf) pour qu'il mette en mémoire tampon tous mes octets et me renvoie un byte[] quand j'ai fini. Existe-t-il une classe qui fait pour les octets ce que StringBuffer fait pour les chaînes de caractères ? Il ne semble pas que la classe ByteBuffer soit celle que je recherche.

Quelqu'un a une bonne solution ?

125voto

Clint Points 5864

Essayez ByteArrayOutputStream . Vous pouvez utiliser write( byte[] ) et il se développera en fonction des besoins.

6 votes

+1 S'est avéré utile pour recevoir des données via un Socket sans avoir à s'embêter avec un tableau.

6 votes

Vous n'êtes pas "obligé d'utiliser write(byte[], int, int)". Il existe deux autres méthodes write().

9voto

Micer Points 936

Pour prolonger la réponse précédente, vous pouvez utiliser Tableau d'octets de sortie (ByteArrayOutputStream) et sa méthode public void write(byte[] b, int off, int len) où les paramètres sont :

b - les données

off - le décalage de début dans les données

len - le nombre d'octets à écrire

Si vous voulez l'utiliser comme un "constructeur d'octets" et insérer un octet à la fois, vous pouvez utiliser ceci :

byte byteToInsert = 100;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(new byte[]{byteToInsert}, 0, 1);

Vous pouvez alors utiliser baos.toString() pour convertir le tableau en chaîne de caractères. L'avantage est que lorsque vous avez besoin de configurer l'encodage de l'entrée, vous pouvez simplement utiliser i.e. :

baos.toString("Windows-1250")

5 votes

Il existe deux autres méthodes write() que vous pouvez appeler. Vous n'avez pas besoin de faire toute cette gymnastique.

0 votes

Merci pour la note, vous avez raison, baos.write(byteToInsert) fait le même travail :-)

3voto

RickHigh Points 424

J'en ai écrit un qui est vraiment facile à utiliser et qui évite de copier beaucoup de tampons de tableaux d'octets.

Il possède une méthode appelée add.

Vous pouvez y ajouter des chaînes de caractères, des octets, des bytes, des longs, des int, des doubles, des flottants, des courts et des caractères.

L'API est facile à utiliser et quelque peu sûre. Elle ne vous permet pas de copier le tampon et n'encourage pas l'utilisation de deux lecteurs.

Il dispose d'un mode de vérification des limites et d'un MODE JE SAIS CE QUE JE FAIS sans vérification des limites.

Le mode de vérification des limites le fait croître automatiquement, ce qui évite tout désagrément.

https://github.com/RichardHightower/boon/wiki/Auto-Growable-Byte-Buffer-like-a-ByteBuilder

Voici un guide complet, étape par étape, sur la façon de l'utiliser. Il est sur github.

Java Boon - Tampon d'octets auto-croissant comme un ByteBuilder

Avez-vous déjà voulu un tableau de tampons facile à utiliser qui se développe automatiquement et/ou vous pouvez lui donner une taille fixe et simplement y ajouter des choses ? Je l'ai fait. J'en ai écrit un aussi.

Regardez Je peux y écrire des chaînes de caractères (il les convertit en UTF-8).

    ByteBuf buf = new ByteBuf();
    buf.add(bytes("0123456789\n"));
    buf.add("0123456789\n");
    buf.add("0123456789\n");
    buf.add("0123456789\n");
    buf.add("0123456789\n");
    buf.add("0123456END\n");

Ensuite, plus tard, je peux lire la chaîne de caractères à partir du tampon :

    String out = new String(buf.readAndReset(), 0, buf.len());
    assertEquals(66, buf.len());
    assertTrue(out.endsWith("END\n"));

Je n'ai jamais à définir la taille du tableau. Il s'agrandira automatiquement selon les besoins et de manière efficace.

Si je sais exactement quelle sera la taille de mes données, je peux économiser un peu de vérification des bornes en utilisant createExact .

    ByteBuf buf = ByteBuf.createExact(66);
    buf.add(bytes("0123456789\n"));
    buf.add("0123456789\n");
    buf.add("0123456789\n");
    buf.add("0123456789\n");
    buf.add("0123456789\n");
    buf.add("0123456END\n");
    assertEquals(66, buf.len());

Si j'utilise l'expression "créer exactement", alors je dis... hé... je sais exactement quelle taille il peut atteindre et il ne dépassera jamais ce chiffre, et s'il le fait... vous pouvez me frapper sur la tête avec un sac de pierres !

Ce qui suit vous frappe à la tête avec un sac de pierres ! LANCE UNE EXCEPTION !!!!

    ByteBuf buf = ByteBuf.createExact(22);
    buf.add(bytes("0123456789\n"));
    buf.add("0123456789\n");
    buf.add("0123456789\n");
    buf.add("0123456789\n");
    buf.add("0123456789\n");
    buf.add("0123456END\n");

Il fonctionne avec des doubles.

    ByteBuf buf = ByteBuf.createExact(8);

    //add the double
    buf.add(10.0000000000001);

    byte[] bytes = buf.readAndReset();
    boolean worked = true;

    worked |= idxDouble(bytes, 0) == 10.0000000000001 || die("Double worked");

Il fonctionne avec le flotteur.

    ByteBuf buf = ByteBuf.createExact(8);

    //add the float
    buf.add(10.001f);

    byte[] bytes = buf.readAndReset();
    boolean worked = true;

    worked |= buf.len() == 4 || die("Float worked");

    //read the float
    float flt = idxFloat(bytes, 0);

    worked |= flt == 10.001f || die("Float worked");

Il fonctionne avec int.

    ByteBuf buf = ByteBuf.createExact(8);

    //Add the int to the array
    buf.add(99);

    byte[] bytes = buf.readAndReset();
    boolean worked = true;

    //Read the int back
    int value = idxInt(bytes, 0);

    worked |= buf.len() == 4 || die("Int worked length = 4");
    worked |= value == 99 || die("Int worked value was 99");

Il fonctionne avec les chars.

    ByteBuf buf = ByteBuf.createExact(8);

    //Add the char to the array
    buf.add('c');

    byte[] bytes = buf.readAndReset();
    boolean worked = true;

    //Read the char back
    int value = idxChar(bytes, 0);

    worked |= buf.len() == 2 || die("char worked length = 4");
    worked |= value == 'c' || die("char worked value was 'c'");

Il fonctionne avec le court.

    ByteBuf buf = ByteBuf.createExact(8);

    //Add the short to the array
    buf.add((short)77);

    byte[] bytes = buf.readAndReset();
    boolean worked = true;

    //Read the short back
    int value = idxShort(bytes, 0);

    worked |= buf.len() == 2 || die("short worked length = 2");
    worked |= value == 77 || die("short worked value was 77");

Il fonctionne même avec des octets.

    ByteBuf buf = ByteBuf.createExact(8);

    //Add the byte to the array
    buf.add( (byte)33 );

    byte[] bytes = buf.readAndReset();
    boolean worked = true;

    //Read the byte back
    int value = idx(bytes, 0);

    worked |= buf.len() == 1 || die("byte worked length = 1");
    worked |= value == 33 || die("byte worked value was 33");

Vous pouvez ajouter toutes sortes de primitives à votre tableau d'octets.

    boolean worked = true;
    ByteBuf buf = ByteBuf.create(1);

    //Add the various to the array
    buf.add( (byte)  1 );
    buf.add( (short) 2 );
    buf.add( (char)  3 );
    buf.add(         4 );
    buf.add( (float) 5 );
    buf.add( (long)  6 );
    buf.add( (double)7 );

    worked |= buf.len() == 29 || die("length = 29");

    byte[] bytes = buf.readAndReset();

    byte myByte;
    short myShort;
    char myChar;
    int myInt;
    float myFloat;
    long myLong;
    double myDouble;

Maintenant, nous vérifions juste que nous pouvons tout relire.

    myByte    =   idx       ( bytes, 0 );
    myShort   =   idxShort  ( bytes, 1 );
    myChar    =   idxChar   ( bytes, 3 );
    myInt     =   idxInt    ( bytes, 5 );
    myFloat   =   idxFloat  ( bytes, 9 );
    myLong   =    idxLong   ( bytes, 13 );
    myDouble  =   idxDouble ( bytes, 21 );

    worked |= myByte   == 1 || die("value was 1");
    worked |= myShort  == 2 || die("value was 2");
    worked |= myChar   == 3 || die("value was 3");
    worked |= myInt    == 4 || die("value was 4");
    worked |= myFloat  == 5 || die("value was 5");
    worked |= myLong   == 6 || die("value was 6");
    worked |= myDouble == 7 || die("value was 7");

Une fois que vous avez appelé

 byte[] bytes = buf.readAndReset() 

alors vous dites que vous avez terminé avec le ByteBuffer !

Une fois que vous demandez les octets, cela devient inutile car le tableau d'octets interne est mis à zéro.

Quand vous appelez readAndReset, il vous donne son tampon. Voici mon état interne, vous pouvez l'avoir, mais je vais le mettre à null pour que personne d'autre ne l'utilise.

C'est bon. Créez-en un autre si vous êtes sûr qu'une seule instance à la fois utilise le tampon (byte []).

Vous pouvez même utiliser le tampon que vous venez d'utiliser comme dans

ByteBuf buf2 = new ByteBuf.create(bytes); 

Ceci est dû au fait qu'aucun tampon n'est copié. ByteBuf écrit dans le tampon que vous lui donnez. Si vous voulez qu'une autre copie soit donnée à ByteBuf, faites ceci :

ByteBuf buf2 = new ByteBuf.create( copy(bytes) ); 

C'est une bénédiction après tout :)

Venez voir Boon. Vous obtenez la classe ci-dessus et les idx, et les idxInt et idxLong gratuitement !

https://github.com/RichardHightower/boon/

0 votes

La première Url (vers le wiki) n'a pas été trouvée.

1voto

RickHigh Points 424

Voyons voir. Il existe la classe ByteBuffer en Java.

http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html

Il possède des méthodes de transfert en masse de séquences contiguës d'octets depuis un tableau d'octets vers des tampons matériels. Cela pourrait faire l'affaire.

Il dispose également de méthodes d'obtention et d'insertion absolues et relatives qui lisent et écrivent des byte[]s et d'autres primitives dans le tampon d'octets.

Il dispose également de méthodes pour compacter, dupliquer et découper un tampon d'octets.

// Creates an empty ByteBuffer with a 1024 byte capacity
ByteBuffer buf = ByteBuffer.allocate(1024);

// Get the buffer's capacity
int capacity = buf.capacity(); // 10

buf.put((byte)0xAA); // position=0

// Set the position
buf.position(500);

buf.put((byte)0xFF);

// Read the position 501
int pos = buf.position(); 

// Get remaining byte count
int remaining = buf.remaining(); (capacity - position)

Il dispose également d'un put en vrac pour mettre un tableau, ce qui est assez proche de l'append que vous demandiez :

public final ByteBuffer put(byte[] src)

Voir : http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#put(byte[])

J'ai écrit ma propre petite librairie pour manipuler les tableaux d'octets :)

Vous pouvez les ajouter comme suit

byte [] a = ...
byte [] b = ...
byte [] c = ...

a = add(a, b);
a = add(a, c);

cela vous donnera tout le contenu de b, et c après le contenu de a.

Si vous vouliez faire pousser un par 21, vous pourriez faire ce qui suit :

a = grow( letters,  21);

Si vous voulez doubler la taille de a, vous pouvez procéder comme suit :

a = grow( letters,  21);

Voir...

https://github.com/RichardHightower/boon/blob/master/src/main/java/org/boon/core/primitive/Byt.java

    byte[] letters =
            arrayOfByte(500);

    assertEquals(
            500,
            len(letters)
    );

Créer

    byte[] letters =
            array((byte)0, (byte)1, (byte)2, (byte)3);

    assertEquals(
            4,
            len(letters)
    );

Index

    byte[] letters =
            array((byte)'a', (byte)'b', (byte)'c', (byte)'d');

    assertEquals(
            'a',
            idx(letters, 0)
    );

    assertEquals(
            'd',
            idx(letters, -1)
    );

    assertEquals(
            'd',
            idx(letters, letters.length - 1)
    );

    idx(letters, 1, (byte)'z');

    assertEquals(
            (byte)'z',
            idx(letters, 1)
    );

Contient

    byte[] letters =
            array((byte)'a',(byte) 'b', (byte)'c', (byte)'d');

    assertTrue(
            in((byte)'a', letters)
    );

    assertFalse(
            in((byte)'z', letters)
    );

Tranche :

    byte[] letters =
            array((byte)'a', (byte)'b', (byte)'c', (byte)'d');

    assertArrayEquals(
            array((byte)'a', (byte)'b'),
            slc(letters, 0, 2)
    );

    assertArrayEquals(
            array((byte)'b', (byte)'c'),
            slc(letters, 1, -1)
    );

    //>>> letters[2:]
    //['c', 'd']
    //>>> letters[-2:]
    //['c', 'd']

    assertArrayEquals(
            array((byte)'c', (byte)'d'),
            slc(letters, -2)
    );

    assertArrayEquals(
            array((byte)'c', (byte)'d'),
            slc(letters, 2)
    );

    //>>> letters[:-2]
    //     ['a', 'b']
    assertArrayEquals(
            array((byte)'a', (byte)'b'),
            slcEnd(letters, -2)
    );

    //>>> letters[:-2]
    //     ['a', 'b']
    assertArrayEquals(
            array((byte)'a',(byte) 'b'),
            slcEnd(letters, 2)
    );

Cultivez

    byte[] letters =
            array((byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e');

    letters = grow( letters,  21);

    assertEquals(
            'e',
            idx(letters, 4)
    );

    assertEquals(
            'a',
            idx(letters, 0)
    );

    assertEquals(
            len(letters),
            26
    );

    assertEquals(
            '\0',
            idx(letters, 20)
    );

Rétrécissement :

    letters =  shrink ( letters, 23 );

    assertArrayEquals(
            array((byte)'a', (byte)'b', (byte)'c'),
            letters

    );

Copie :

    assertArrayEquals(
            array((byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e'),
            copy(array((byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e'))

    );

Ajouter :

    assertArrayEquals(
            array((byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'),
            add(array((byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e'), (byte)'f') );

L'add les additionne en fait en utilisant System.arraycopy (ce qui pourrait être dangereux, mais pas encore).

Ajouter un tableau à un autre :

    assertArrayEquals(
            array(     (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'),
            add( array((byte)'a', (byte)'b', (byte)'c', (byte)'d'), array((byte)'e', (byte)'f') )

    );

Insérer :

    assertArrayEquals(
            array((byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g'),
            insert( array((byte)'a', (byte)'b', (byte)'d', (byte)'e', (byte)'f', (byte)'g'), 2, (byte)'c' )

    );

    assertArrayEquals(
            array((byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g'),
            insert( array((byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g'), 0, (byte)'a' )

    );

    assertArrayEquals(
            array((byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g'),
            insert( array((byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'g'), 5, (byte)'f' )

    );

Voici un aperçu de quelques-unes de ces méthodes :

public static byte[] grow(byte [] array, final int size) {
    Objects.requireNonNull(array);

    byte [] newArray  = new byte[array.length + size];
    System.arraycopy(array, 0, newArray, 0, array.length);
    return newArray;
}

public static byte[] grow(byte [] array) {
    Objects.requireNonNull(array);

    byte [] newArray  = new byte[array.length *2];
    System.arraycopy(array, 0, newArray, 0, array.length);
    return newArray;
}

public static byte[] shrink(byte[] array, int size) {
    Objects.requireNonNull(array);

    byte[] newArray = new byte[array.length - size];

    System.arraycopy(array, 0, newArray, 0, array.length-size);
    return newArray;
}

public static byte[] copy(byte[] array) {
    Objects.requireNonNull(array);
    byte[] newArray = new byte[array.length];
    System.arraycopy(array, 0, newArray, 0, array.length);
    return newArray;
}

public static byte[] add(byte[] array, byte v) {
    Objects.requireNonNull(array);
    byte[] newArray = new byte[array.length + 1];
    System.arraycopy(array, 0, newArray, 0, array.length);
    newArray[array.length] = v;
    return newArray;
}

public static byte[] add(byte[] array, byte[] array2) {
    Objects.requireNonNull(array);
    byte[] newArray = new byte[array.length + array2.length];
    System.arraycopy(array, 0, newArray, 0, array.length);
    System.arraycopy(array2, 0, newArray, array.length, array2.length);
    return newArray;
}

public static byte[] insert(final byte[] array, final int idx, final byte v) {
    Objects.requireNonNull(array);

    if (idx >= array.length) {
        return add(array, v);
    }

    final int index = calculateIndex(array, idx);

    //Object newArray = Array.newInstance(array.getClass().getComponentType(), array.length+1);
    byte [] newArray = new byte[array.length+1];

    if (index != 0) {
        /* Copy up to the location in the array before the index. */
        /*                 src     sbegin  dst       dbegin   length of copy */
        System.arraycopy( array,   0,      newArray, 0,       index );
    }

    boolean lastIndex = index == array.length -1;
    int remainingIndex = array.length - index;

    if (lastIndex ) {
        /* Copy the area after the insert. Make sure we don't write over the end. */
        /*                 src  sbegin   dst       dbegin     length of copy */
        System.arraycopy(array, index,   newArray, index + 1, remainingIndex );

    } else {
        /* Copy the area after the insert.  */
        /*                 src  sbegin   dst       dbegin     length of copy */
        System.arraycopy(array, index,   newArray, index + 1, remainingIndex );

    }

    newArray[index] = v;
    return  newArray;
}

public static byte[] insert(final byte[] array, final int fromIndex, final byte[] values) {
    Objects.requireNonNull(array);

    if (fromIndex >= array.length) {
        return add(array, values);
    }

    final int index = calculateIndex(array, fromIndex);

    //Object newArray = Array.newInstance(array.getClass().getComponentType(), array.length+1);
    byte [] newArray = new byte[array.length +  values.length];

    if (index != 0) {
        /* Copy up to the location in the array before the index. */
        /*                 src     sbegin  dst       dbegin   length of copy */
        System.arraycopy( array,   0,      newArray, 0,       index );
    }

    boolean lastIndex = index == array.length -1;

    int toIndex = index + values.length;
    int remainingIndex = newArray.length - toIndex;

    if (lastIndex ) {
        /* Copy the area after the insert. Make sure we don't write over the end. */
        /*                 src  sbegin   dst       dbegin     length of copy */
        System.arraycopy(array, index,   newArray, index + values.length, remainingIndex );

    } else {
        /* Copy the area after the insert.  */
        /*                 src  sbegin   dst       dbegin     length of copy */
        System.arraycopy(array, index,   newArray, index + values.length, remainingIndex );

    }

    for (int i = index, j=0; i < toIndex; i++, j++) {
        newArray[ i ] = values[ j ];
    }
    return  newArray;
}

Plus....

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X