问题描述
最近我创建了一个包装器来读取和写入数据到一个byte
数组中。
为此,我一直在使用ArrayList<Byte>
,但我想知道这是否是最有效的方法,因为:
-
addAll()
不适用于byte
数组(即使使用Arrays.asList()
,它返回我List<Byte[]>
)。 为了修复它,我只是循环并在每个循环中添加一个byte
,但我想这假设了很多函数调用,因此它具有性能成本。 -
从
ArrayList
获取byte[]
ArrayList
发生同样的情况。 我无法从Byte[]
为byte[]
,所以我必须使用循环。 - 我想存储 Byte 而不是 byte 会使用更多的内存。
我知道ByteArrayInputStream
和ByteArrayOutputStream
可以用于此,但它有一些不便:
-
我想实现以不同字节顺序读取不同数据类型的方法(例如,
readInt
、readLEInt
、readUInt
等),而这些类只能读/写一个字节或一个字节数组。 这不是真正的问题,因为我可以在包装器中修复它。 但是第二个问题来了。 -
我希望能够同时写入和读取,因为我正在使用它来解压缩一些文件。
所以要为它创建一个包装器,我需要同时包含
ByteArrayInputStream
和ByteArrayOutputStream
。 我不知道这些是否可以以某种方式同步,或者我每次写入包装器时都必须将一个的整个数据写入另一个。
所以,我的问题来了:使用ByteBuffer
会更有效吗?
我知道您可以从中获取integers
、 floats
等,甚至可以更改字节顺序。
我想知道的是,在使用ByteBuffer
和ArrayList<Byte>
之间是否存在真正的性能变化。
1楼
绝对是ByteBuffer或ByteArrayOutputStream 。 在您的情况下似乎很好。 检查 Javadoc,因为它有很好的方法,对于 putInt/getInt 等,您可能想要设置顺序(这 4 个字节)
byteBuffer.order(ByteBuffer.LITTLE_ENDIAN);
对于文件,您可以使用getChannel()
或变体,然后使用MappedByteBuffer
。
ByteBuffer 可以包装一个字节数组,或分配。
2楼
请记住,每个对象都有与之相关的开销,包括每个对象的一些内存和超出范围后的垃圾收集。
使用List<Byte>
意味着每字节创建/垃圾收集一个对象,这是非常浪费的。
3楼
ByteBuffer 是一个围绕字节数组的包装类,它不像 ArrayList 那样具有动态大小,但它每字节消耗更少的内存并且速度更快。 如果你知道你需要的大小,那么使用 ByteBuffer,如果你不知道,那么你可以使用 ByteArrayOutputStream(并且可能被 ObjectOutputStream 包裹,它有一些方法来写入不同类型的数据)。 要读取您写入 ByteArrayOutputStream 的数据,您可以扩展 ByteArrayOutputStream,然后您可以访问字段 buf[] 和计数,这些字段是受保护的,因此您可以从扩展类访问它们,它看起来像:
public class ByteArrayOutputStream extends OutputStream {
/**
* The buffer where data is stored.
*/
protected byte buf[];
/**
* The number of valid bytes in the buffer.
*/
protected int count;
...
}
public class ReadableBAOS extends ByteArrayOutputStream{
public byte readByte(int index) {
if (count<index) {
throw new IndexOutOfBoundsException();
}
return buf[index];
}
}
所以你可以在你的扩展类中创建一些方法来从底层缓冲区读取一些字节,而无需像 toByteArray() 方法那样每次都复制其内容。