12

我正在声明一个大小未知的字节数组,因为它不断更新,那么我如何声明无限大小/可变大小的字节数组?

4

10 回答 10

12

您不能声明一个无限大小的数组,因为这需要无限的内存。此外,所有分配调用都处理数字,而不是无限量。

您可以分配一个按需调整大小的字节缓冲区。我相信最简单的选择是ByteArrayOutputStream.

ByteBuffer有一个 API 可以更轻松地操作缓冲区,但您必须自己构建调整大小功能。最简单的方法是分配一个新的、更大的数组,复制旧的内容,然后用新的缓冲区交换旧的。

其他答案已经提到使用List<Byte>某种。值得注意的是,如果你创建了一堆new Byte()对象,你会显着增加内存消耗。 Byte.valueOf回避了这个问题,但您必须确保在整个代码中始终使用它。如果您打算在许多地方使用此列表,我可能会考虑编写一个简单的List装饰器来实习所有元素。例如:

public class InterningList extends AbstractList<Byte>
{
    ...
    @Override
    public boolean add(Byte b) {
        return super.add(Byte.valueOf(b));
    }
    ...
}

这不是一个完整的(甚至是经过测试的)示例,只是一个开始......

于 2012-11-25T18:58:14.300 回答
11

Java 中的数组不是动态的。您可以改用列表。

List<Byte> list = new ArrayList<Byte>();

由于自动装箱功能,您可以自由地将字节对象或原始字节添加到此列表中。

于 2012-11-25T18:57:30.630 回答
5

要定义不同长度的字节数组,只需使用 apachecommons.io.IOUtils库而不是像分配手动长度一样

byte[] b=new byte[50];

您可以将输入流传递给IOUtils函数,该函数将对此输入流执行读取函数,因此字节数组将根据需要具有精确的字节长度。前任。

byte[] b = IOUtils.toByteArray(inpustream);

混乱..

于 2013-05-27T10:58:56.150 回答
2

ByteArrayOutputStream将允许写入动态字节数组。但是,无法使用移除、替换和插入等方法。必须提取字节数组,然后直接对其进行操作。

于 2015-02-26T17:26:36.573 回答
1

最好的选择是使用 ArrayList。当你填充它时它会调整大小。

List<Byte> array = new ArrayList<Byte>();

于 2012-11-25T18:58:01.747 回答
1

显而易见的解决方案是使用 ArrayList。

但如果您需要性能或内存受限,这是一个糟糕的解决方案,因为它实际上存储的不是字节而是字节(即对象)。

对于任何实际应用程序,答案很简单:您必须自己管理字节数组,通过使用使其在必要时增长的方法。如果需要,您可以将其嵌入到特定的类中:

public class AlmostInfiniteByteArray {

    private byte[] array;
    private int size;

    public AlmostInfiniteByteArray(int cap) {
        array = new byte[cap];
            size = 0;
    }

    public int get(int pos) {
        if (pos>=size) throw new ArrayIndexOutOfBoundsException();
        return array[pos];
    }

    public void set(int pos, byte val) {
        if (pos>=size) {
            if (pos>=array.length) {
                byte[] newarray = new byte[(pos+1)*5/4];
                System.arraycopy(array, 0, newarray, 0, size);
                array = newarray;
            }
            size = pos+1;
        }
        array[pos] = val;
    }
}
于 2012-11-25T19:03:06.103 回答
0

我会稍微调整其他人的答案。

创建一个 LargeByteArray 类来管理您的数组。无论您需要什么,它都会有 get 和 set 方法等。

在幕后,该类将使用 long 来保存当前长度并使用 ArrayList 来存储数组的内容。

我会选择在 ArrayList 中存储 byte[8192] 或 byte[16384] 数组。这将在浪费的大小方面进行合理的权衡,并减少调整大小的需要。

您甚至可以使数组“稀疏”,即仅在该框中存储非零值时才分配 list.get(index/8192) 条目。

在某些情况下,这样的结构可以为您提供更多的存储空间。

您可以使用的另一种策略是在写入后压缩 byte[] 框并在读取前解压缩(使用 LRU 缓存进行读取),这可以允许存储两倍或更多可用内存...尽管这取决于压缩策略。

之后,您可以查看将一些框分页到磁盘...

这与我可以得到的无限数组一样接近;-)

于 2012-11-25T19:36:27.517 回答
0

正如 Prashant 已经说过的,您可以从一块使用 IOUtils。

这是可以解决任务的一小部分(您将需要 IOUtils.toByteArray):

public class IOUtils {

private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;

public static byte[] toByteArray(InputStream input) throws IOException {
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    copy(input, output);
    return output.toByteArray();
}

public static int copy(InputStream input, OutputStream output)
        throws IOException {
    long count = copyLarge(input, output);
    if (count > Integer.MAX_VALUE) {
        return -1;
    }
    return (int) count;
}

public static long copyLarge(InputStream input, OutputStream output)
        throws IOException {
    byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
    long count = 0;
    int n = 0;
    while (-1 != (n = input.read(buffer))) {
        output.write(buffer, 0, n);
        count += n;
    }

    return count;

}
}
于 2013-12-11T22:15:05.827 回答
0

使用List的任何子类型的ArrayList

List 的不同实现可以让你在列表上做不同的事情(例如不同的遍历策略,不同的性能等)

于 2012-11-25T18:58:55.630 回答
0

ArrayList 的初始容量为 10。您可以通过 ArrayList(5000) 更改它。ArrayList 将在需要时将其大小加倍(它将创建新数组并将旧数组复制到新数组)。

于 2012-11-25T19:01:25.660 回答