【问题标题】:Byte array of unknown length in javajava中未知长度的字节数组
【发布时间】:2010-10-14 10:39:52
【问题描述】:

我在 java 中构造一个字节数组,但我不知道这个数组会有多长。

我想要一些像 Java 的 StringBuffer 这样的工具,您可以调用 .append(byte b) 或 .append(byte[] buf) 并让它缓冲我所有的字节,并在我完成后返回给我一个字节数组。是否有一个类可以像 StringBuffer 一样为字节做字符串?它看起来不像 ByteBuffer 类是我正在寻找的。​​p>

谁有好的解决方案?

【问题讨论】:

    标签: java buffer byte


    【解决方案1】:

    试试ByteArrayOutputStream。您可以使用write( byte[] ),它会根据需要增长。

    【讨论】:

    • +1 被证明对通过 Socket 接收数据而不用弄乱数组很有用。
    • 您不必“必须使用 write(byte[], int, int)”。还有另外两个 write() 方法。
    【解决方案2】:

    只是为了扩展之前的答案,您可以使用ByteArrayOutputStream 和它的方法public void write(byte[] b, int off, int len),其中参数是:

    b - 数据

    off - 数据中的起始偏移量

    len - 要写入的字节数

    如果你想将它用作“字节构建器”并逐字节插入,你可以使用这个:

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

    然后你可以使用baos.toString() 方法将数组转换为字符串。好处是当你需要设置输入的编码时,你可以简单地使用 i.e.:

    baos.toString("Windows-1250")
    

    【讨论】:

    • 您可以调用另外两个 write() 方法。你不必经历所有这些体操。
    • 感谢您的注意,您是对的,baos.write(byteToInsert) 做同样的工作。 :-)
    【解决方案3】:

    让我们看看。 Java中有ByteBuffer类。

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

    它具有将连续字节序列从字节数组传输到硬件缓冲区的批量方法。它会成功的。

    它还具有绝对和相对 get 和 put 方法,用于读取和写入 byte[]s 和其他原语到 / 用于字节缓冲区。

    它还具有压缩、复制和切片字节缓冲区的方法。

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

    它还有一个大容量 put 来放置一个数组,它非常接近您要求的附加:

    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 的所有内容,以及 a 的内容之后的 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)
        );
    

    切片:

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

    更多....

    【讨论】:

      【解决方案4】:

      我写了一个非常好用的,并且避免了大量的字节数组缓冲区复制。

      它有一个叫做 add 的方法。

      您可以向其添加字符串、字节、字节、long、int、double、float、short 和 chars。

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

      它适用于字符。

          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 时,它会为您提供缓冲区。这是我的内部状态,你可以拥有它,但我将它设置为 null,这样其他人就不会使用它了。

      没关系。如果您确定一次只有一个实例在使用缓冲区(字节 []),请创建另一个。

      您甚至可以像在

      中那样使用刚刚使用的缓冲区
      ByteBuf buf2 = new ByteBuf.create(bytes); 
      

      这是因为没有缓冲区被复制。 ByteBuf 写入你给它的缓冲区。 如果您希望将另一个副本提供给 ByteBuf,请执行以下操作:

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

      这毕竟是福音。 :)

      快来看看吧。您可以免费获得上述类和 idx,以及 idxInt 和 idxLong!

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

      【讨论】:

      • 未找到第一个 URL(到 wiki)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-01
      • 1970-01-01
      • 2018-11-13
      相关资源
      最近更新 更多