web-dev-qa-db-fra.com

Tableau d'octets de longueur inconnue dans java

Je construis un tableau d'octets en Java et je ne sais pas combien de temps le tableau sera.

Je veux un outil comme StringBuffer de Java que vous pouvez simplement appeler .append (octet b) ou .append (octet [] buf) et le mettre en mémoire tampon tous mes octets et me renvoyer un tableau d'octets lorsque j'ai terminé. Existe-t-il une classe qui fait pour les octets ce que StringBuffer fait pour les chaînes? Il ne semble pas que la classe ByteBuffer soit ce que je recherche.

Quelqu'un a une bonne solution?

67
jbu

Essayez ByteArrayOutputStream . Vous pouvez utiliser write( byte[] ) et il s'agrandira au besoin.

110
Clint

Juste pour étendre la réponse précédente, vous pouvez utiliser 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 souhaitez l'utiliser comme un "générateur d'octets" et insérer octet par octet, vous pouvez utiliser ceci:

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

Ensuite, vous pouvez utiliser la méthode baos.toString() pour convertir le tableau en chaîne. L'avantage est que lorsque vous devez configurer le codage de l'entrée, vous pouvez simplement utiliser, c'est-à-dire:

baos.toString("Windows-1250")
6
Micer

J'en ai écrit un qui est vraiment facile à utiliser et évite beaucoup de copie de tampon de tableau d'octets.

Il a une méthode appelée add.

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

L'API est facile à utiliser et quelque peu sûre. Il ne vous permet pas de copier le tampon et ne favorise pas la présence de deux lecteurs.

Il a un mode de vérification des limites et un mode JE SAIS CE QUE JE FAIS sans vérification des limites.

Le mode de vérification des limites l'agrandit automatiquement pour qu'il n'y ait pas de soucis.

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

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

Java Boon - Tampon d'octets évolutif automatique comme un ByteBuilder

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

Regardez .. Je peux y écrire des chaînes (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 dans le 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 se développera automatiquement au besoin de manière efficace.

Si je sais exactement la taille de mes données, je peux enregistrer certaines limites en vérifiant 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 create exact, alors je dis ... hé ... Je sais exactement à quel point il peut grandir et il ne dépassera jamais ce nombre et si c'est le cas ... vous pouvez me frapper la tête avec un sac de roches!

Ce qui suit vous frappe au-dessus de 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 float.

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

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

Cela fonctionne avec le caractère.

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

Cela fonctionne avec 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 simplement que nous pouvons tout lire.

    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 appelez

 byte[] bytes = buf.readAndReset() 

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

Une fois que vous avez demandé les octets, cela devient inutile car il ne définit rien dans le tableau d'octets interne.

Lorsque 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 simplement une autre si vous êtes sûr qu'une seule instance à la fois utilise le tampon (octet []).

Vous pouvez même utiliser le tampon que vous utilisiez comme dans

ByteBuf buf2 = new ByteBuf.create(bytes); 

En effet, aucun tampon n'est copié. ByteBuf écrit dans le tampon que vous lui donnez. Si vous souhaitez donner une autre copie à ByteBuf, procédez comme suit:

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

C'est une aubaine après tout. :)

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

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

4
RickHigh

Voyons voir. Il existe la classe ByteBuffer en Java.

http://docs.Oracle.com/javase/7/docs/api/Java/nio/ByteBuffer.html

Il a des méthodes en vrac qui transfèrent des séquences contiguës d'octets d'un tableau d'octets vers des tampons matériels. Ça ferait l'affaire.

Il possède également des méthodes get et put absolues et relatives qui lisent et écrivent les octets [] et d'autres primitives dans/pour le tampon d'octets.

Il dispose également de méthodes de compactage, de duplication et de découpage d'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 a également un gros volume pour mettre un tableau, ce qui est assez proche de l'ajout que vous demandiez:

public final ByteBuffer put(byte[] src)

Voir: http://docs.Oracle.com/javase/7/docs/api/Java/nio/ByteBuffer.html#put (octet [])

J'ai écrit ma propre petite lib pour manipuler des tableaux d'octets. :)

Vous pouvez les ajouter comme ça

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

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

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

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

a = grow( letters,  21);

Si vous souhaitez doubler la taille d'un, 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)
    );

Indice

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

Croître

    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écir:

    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'addition les ajoute en fait à l'aide de System.arraycopy (considérant dangereux, mais pas encore).

Ajoutez 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 des 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....

2
RickHigh