Java 中未知长度的字节数组

我正在用 java 构建一个字节数组,我不知道这个数组会有多长。

我想要一些像 Java 的 StringBuffer 这样的工具,你可以直接调用它。附加(字节 b)或。Append (byte [] buf)并让它缓冲所有字节,并在完成后返回一个 byte []。有没有一个类可以像 StringBuffer 一样处理字节?它看起来不像 ByteBuffer 类是我要寻找的。

有人有好办法吗?

68207 次浏览

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

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

数据

数据中的起始偏移量

Len-要写入的字节数

如果你想使用它作为一个“字节构建器”并一个字节一个字节地插入,你可以这样做:

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

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

baos.toString("Windows-1250")

让我们看看,在 Java 中有一个 ByteBuffer 类。

Http://docs.oracle.com/javase/7/docs/api/java/nio/bytebuffer.html

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

它还具有绝对和相对 get 和 put 方法,这些方法读取和写入字节[] 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。

如果你想在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;
}

更多..。

我写了一个非常容易使用,并避免了很多字节数组缓冲区复制。

它有一个名为 add 的方法。

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

该 API 易于使用,并且在某种程度上是故障安全的。它不允许您复制周围的缓冲区,并且不提倡拥有两个读取器。

它有一个边界检查模式和一个我知道我在做什么没有边界检查模式。

边界检查模式自动增长,所以没有麻烦。

Https://github.com/richardhightower/boon/wiki/auto-growable-byte-buffer-like-a-bytebuilder

下面是如何使用它的完整步骤指南。

Java Boon-自动增长的字节缓冲像一个字节生成器

你曾经想要一个容易使用的缓冲区数组,自动增长和/或你可以给它一个固定的大小,只是添加东西到它?是的。我也写了一首。

看. . 我可以写字符串到它(它转换成 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:

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

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

它与 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()

那么你就是说你已经用完了字节缓冲器!

一旦请求字节,它就变得毫无用处,因为它将内部字节数组设置为空值。

当您调用 readAndReset 时,它正在为您提供它的缓冲区。这是我的内部状态,你可以拥有它,但我要设置为空,所以没有人使用它。

没事的。如果您确定一次只有一个实例在使用缓冲区(byte []) ,那么只需创建另一个实例。

您甚至可以使用刚才使用的缓冲区

ByteBuf buf2 = new ByteBuf.create(bytes);

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

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

这毕竟是恩惠。 :)

来看看 boon 吧,你可以免费得到上面的类和 idx,以及 idxInt 和 idxLong!

Https://github.com/richardhightower/boon/