简体   繁体   English

如何在Java中声明无限大小/动态的字节数组?

[英]How to Declare a Byte Array of Infinite Size/Dynamic in Java?

我声明的字节数组在不断更新时对我来说是未知的,那么如何声明无限大小/可变大小的字节数组呢?

You cannot declare an array of infinite size, as that would require infinite memory. 您不能声明无限大小的数组,因为这将需要无限的内存。 Additionally, all the allocation calls deal with numbers, not infinite quantities. 此外,所有分配调用都处理数字,而不是无限数量。

You can allocate a byte buffer that resizes on demand. 您可以分配一个按需调整大小的字节缓冲区。 I believe the easiest choice would be a ByteArrayOutputStream . 我相信最简单的选择是ByteArrayOutputStream

ByteBuffer has an API which makes manipulation of the buffer easier, but you would have to build the resize functionality yourself. ByteBuffer具有一个使缓冲区的操作更加容易的API,但是您必须自己构建调整大小功能。 The easiest way will be to allocate a new, larger array, copy the old contents in, and swap the new buffer for the old. 最简单的方法是分配一个更大的新数组,复制旧内容,并将新缓冲区替换为旧缓冲区。

Other answers have mentioned using a List<Byte> of some sort. 其他答案提到了使用某种List<Byte>的情况。 It is worth noting that if you create a bunch of new Byte() objects, you can dramatically increase memory consumption. 值得注意的是,如果创建了一堆new Byte()对象,则可以大大增加内存消耗。 Byte.valueOf sidesteps this problem, but you have to ensure that it is consistently used throughout your code. Byte.valueOf此问题,但是您必须确保在整个代码中始终使用它。 If you intend to use this list in many places, I might consider writing a simple List decorator which interns all the elements. 如果您打算在许多地方使用此列表,我可能会考虑编写一个简单的List装饰器,该装饰器可以插入所有元素。 For example: 例如:

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

This is not a complete (or even tested) example, just something to start with... 这不是一个完整(甚至没有经过测试)的示例,只是一些开头...

Arrays in Java are not dynamic. Java中的数组不是动态的。 You can use list instead. 您可以改用列表。

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

Due to autoboxing feature you can freely add either Byte objects or primitive bytes to this list. 由于具有自动装箱功能,您可以将Byte对象或原始字节自由添加到此列表中。

To define a bytearray of varying length just use the apache commons.io.IOUtils library instead of assigning manual length like 要定义不同长度的commons.io.IOUtils只需使用apache commons.io.IOUtils库,而不是像

byte[] b=new byte[50];

You can pass your input stream to IOUtils function which will perform a read function on this inputstream thus byte array will have exact length of bytes as required. 您可以将输入流传IOUtils函数,该函数将对该输入流执行读取功能,因此字节数组将具有所需的确切字节长度。 ex. 例如

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

Chaos.. 混沌..

Your best bet is to use an ArrayList. 最好的选择是使用ArrayList。 As it resizes as you fill it. 当它随着您的填充而调整大小时。

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

The obvious solution would be to use an ArrayList. 显而易见的解决方案是使用ArrayList。

But this is a bad solution if you need performance or are constrained in memory, as it doesn't really store bytes but Bytes (that is, objects). 但是,如果您需要性能或内存受限,这将是一个糟糕的解决方案,因为它实际上并不存储字节,而是存储字节(即对象)。

For any real application, the answer is simple : you have to manage yourself the byte array, by using methods making it grow as necessary. 对于任何实际应用程序,答案很简单:您必须管理字节数组,方法是使字节数组根据需要增长。 You may embed it in a specific class if needed : 如果需要,您可以将其嵌入特定的类中:

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

ByteArrayOutputStream will allow for writing to a dynamic byte array. ByteArrayOutputStream将允许写入动态字节数组。 However, methods such as remove, replace and insert are not available. 但是,诸如删除,替换和插入之类的方法不可用。 One has to extract the byte array and then manipulate it directly. 必须提取字节数组,然后直接对其进行操作。

Use an ArrayList of any subtype of List 使用List的任何子类型的ArrayList

The different implementations of List can allow you to do different things on the list (eg different traversal strategy, different performance etc) List的不同实现可以使您在列表上执行不同的操作(例如,不同的遍历策略,不同的性能等)

Initial capacity of ArrayList is 10. You can change it by ArrayList(5000). ArrayList的初始容量为10。可以通过ArrayList(5000)进行更改。 ArrayList will double it's size when needed (it will create new array and copy the old one to to the new one). ArrayList将在需要时将其大小加倍(它将创建新的数组并将旧的数组复制到新的数组)。

I would tweak slightly other people's answers. 我会稍微调整其他人的答案。

Create a LargeByteArray class to manage your array. 创建LargeByteArray类来管理您的数组。 It will have get and set methods, etc, whatever you will need. 无论您需要什么,它都会具有get和set方法等。

Behind the scenes that class will use a long to hold the current length and use an ArrayList to store the contents of the array. 在后台,该类将使用long来保持当前长度,并使用ArrayList来存储数组的内容。

I would pick to store byte[8192] or byte[16384] arrays in the ArrayList. 我选择将byte [8192]或byte [16384]数组存储在ArrayList中。 That will give a reasonable trade off in terms of size wasted and reduce the need for resizing. 这将在浪费尺寸方面进行合理的权衡,并减少调整大小的需求。

You can even make the array 'sparse' ie only allocate the list.get(index/8192) entry if there is a non-zero value stored in that box. 您甚至可以使数组“稀疏”,即,如果该框中存储的值非零,则仅分配list.get(index / 8192)条目。

Such a structure can give you significantly more storage in some cases. 在某些情况下,这种结构可以为您提供更多的存储空间。

Another strategy you can use is to compress the byte[] boxes after write and uncompress before read (use a LRU cache for reading) which can allow storing twice or more than available ram... Though that depends on the compression strategy. 您可以使用的另一种策略是在写入后压缩byte []框,并在读取之前解压缩(使用LRU高速缓存进行读取),这可以允许存储比可用内存多两倍或更多的内存...尽管这取决于压缩策略。

After that you can look at paging some boxes out to disk... 之后,您可以查看将一些盒子分页到磁盘上。

That's as close to an infinite array as I can get you ;-) 我可以让你接近无限数组;-)

You can make use of IOUtils from piece, as Prashant already told. 正如Prashant已经讲过的,您可以使用块中的IOUtils。

Here's a little piece from it which can solve the task (you will need IOUtils.toByteArray): 这是可以解决任务的一小部分(您将需要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;

}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM