Массив байтов неизвестной длины в Java - PullRequest
66 голосов
/ 20 марта 2009

Я создаю массив байтов в Java, и я не знаю, как долго массив будет.

Мне нужен какой-то инструмент, такой как Java StringBuffer, который вы можете просто вызвать .append (byte b) или .append (byte [] buf) и сделать так, чтобы он буферизовал все мои байты и вернул мне массив байтов, когда я закончил. Есть ли класс, который делает для байтов то, что StringBuffer делает для строк? Не похоже, что я ищу класс ByteBuffer.

У кого-нибудь есть хорошее решение?

Ответы [ 4 ]

107 голосов
/ 20 марта 2009

Попробуйте ByteArrayOutputStream. Вы можете использовать write( byte[] ), и он будет расти по мере необходимости.

6 голосов
/ 28 сентября 2013

Просто для расширения предыдущего ответа вы можете использовать ByteArrayOutputStream и его метод public void write(byte[] b, int off, int len), где параметры:

б - данные

off - начальное смещение в данных

len - количество байтов для записи

Если вы хотите использовать его как «конструктор байтов» и вставлять побайтно, вы можете использовать это:

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

Затем вы можете использовать метод baos.toString() для преобразования массива в строку. Преимущество в том, что когда вам нужно настроить кодировку ввода, вы можете просто использовать i.e.:

baos.toString("Windows-1250")
4 голосов
/ 24 октября 2013

Я написал один, который действительно прост в использовании и позволяет избежать большого количества копий буфера массива байтов.

У него есть один метод с именем add.

Вы можете добавить к нему строки, байты, байты, long, int, double, float, short и char.

API прост в использовании и несколько отказоустойчив. Он не позволяет копировать буфер и не способствует наличию двух читателей.

Он имеет режим проверки границ и Я ЗНАЮ, ЧТО Я ДЕЛАЮ РЕЖИМ, без проверки границ.

Режим проверки границ автоматически увеличивает его, так что нет никаких хлопот.

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

Вот полное пошаговое руководство по его использованию. Это на github.

Java Boon - автоматически растущий байтовый буфер как ByteBuilder

Вы когда-нибудь хотели иметь простой в использовании буферный массив, который автоматически увеличивается и / или вы можете задать ему фиксированный размер и просто добавить к нему материал? Я имею. Я тоже написал один.

Смотри .. Я могу записать в него строки (он конвертирует их в 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");

Потом я смогу прочитать строку из буфера:

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

Мне никогда не нужно устанавливать размер массива. Он будет автоматически расти по мере необходимости эффективным образом.

Если я точно знаю, насколько большими будут мои данные, я могу сохранить некоторые проверки границ с помощью 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());

Если я использую метод создания точных, то я говорю ... эй .. Я точно знаю, насколько он может вырасти, и он никогда не превысит это число, и если это произойдет ... вы можете ударить меня по голове с мешком камней!

Следующий ударяет вас по голове мешком камней! БРОСАЕТ ИСКЛЮЧЕНИЕ !!!!

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

Работает с двойными.

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

Работает с плавающей точкой.

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

Работает с 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");

Работает с char.

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

Работает с короткими.

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

Он работает даже с байтами.

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

Вы можете добавить всевозможные примитивы в ваш байтовый массив.

    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;

Теперь мы просто проверяем, что можем прочитать все обратно.

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

Как только вы позвоните

 byte[] bytes = buf.readAndReset() 

тогда вы говорите, что закончили с ByteBuffer!

Как только вы запрашиваете байты, он становится бесполезным, поскольку устанавливает нулевой внутренний массив байтов.

Когда вы вызываете readAndReset, он дает вам свой буфер. Вот мое внутреннее состояние, вы можете иметь его, но я собираюсь установить его на ноль, чтобы никто другой не использовал его.

Все в порядке. Просто создайте другой, если вы уверены, что только один экземпляр одновременно использует буфер (byte []).

Вы даже можете использовать буфер, который вы использовали, как в

ByteBuf buf2 = new ByteBuf.create(bytes); 

Это потому, что ни один буфер не копируется. ByteBuf пишет в буфер, который вы ему даете. Если вы хотите, чтобы другая копия была передана ByteBuf, сделайте следующее:

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

В конце концов, это благо. :)

Заходите, проверьте благо. Вы получаете вышеупомянутый класс и idx, а также idxInt и idxLong бесплатно!

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

2 голосов
/ 20 октября 2013

Посмотрим. В Java есть класс ByteBuffer.

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

Он имеет массовые методы, которые передают непрерывные последовательности байтов из байтового массива в аппаратные буферы. Это бы сработало.

Он также имеет абсолютные и относительные методы get и put, которые читают и записывают байты [] и другие примитивы в / для байтового буфера.

Также есть методы для сжатия, дублирования и нарезки байтового буфера.

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

У него также есть масса для размещения массива, который очень близок к тому добавлению, о котором вы просили:

public final ByteBuffer put(byte[] src)

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

Я написал свою маленькую библиотеку для работы с байтовыми массивами. :)

Вы можете добавить их вот так

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

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

это даст вам все содержимое b, а c после содержимого a.

Если вы хотите увеличить на 21, вы можете сделать следующее:

a = grow( letters,  21);

Если вы хотите удвоить размер a, вы можете сделать следующее:

a = grow( letters,  21);

См ...

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

    byte[] letters =
            arrayOfByte(500);

    assertEquals(
            500,
            len(letters)
    );

Создать

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

    assertEquals(
            4,
            len(letters)
    );

Индекс

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

Содержит

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


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

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

Slice:

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

Расти

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

Сжать:

    letters =  shrink ( letters, 23 );

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

    );

Копия:

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

    );

Добавить:

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

Надстройка фактически добавляет их вместе с помощью System.arraycopy (с учетом небезопасного, но пока нет).

Добавить один массив в другой:

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

    );

Вставка:

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

    );

Вот несколько методов:

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

Подробнее ....

...