web-dev-qa-db-fra.com

Comment déclarer un tableau d'octets de taille infinie/dynamique en Java?

Je déclare un tableau d'octets dont la taille est inconnue car il continue à se mettre à jour. Comment puis-je déclarer le tableau d'octets de taille infinie/taille variable?

10
NewCoder

Les tableaux en Java ne sont pas dynamiques. Vous pouvez utiliser la liste à la place.

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

En raison de la fonctionnalité de sélection automatique, vous pouvez librement ajouter des objets ou des octets primitifs à cette liste.

6
Juvanis

Vous ne pouvez pas déclarer un tableau de taille infinie, car cela nécessiterait une mémoire infinie. De plus, tous les appels d’allocation portent sur des numéros et non sur des quantités infinies.

Vous pouvez allouer un tampon d'octets qui redimensionne à la demande. Je crois que le choix le plus facile serait un ByteArrayOutputStream .

ByteBuffer a une API qui facilite la manipulation du tampon, mais vous devrez créer la fonctionnalité de redimensionnement vous-même. Le moyen le plus simple consiste à allouer un nouveau tableau plus grand, à copier l'ancien contenu dans et à remplacer le nouveau tampon par l'ancien.

D'autres réponses ont mentionné l'utilisation d'un List<Byte> d'une certaine sorte. Il est à noter que si vous créez un ensemble d'objets new Byte(), vous pouvez augmenter considérablement la consommation de mémoire. Byte.valueOf évite ce problème, mais vous devez vous assurer qu'il est utilisé de manière cohérente dans tout votre code. Si vous avez l’intention d’utiliser cette liste dans de nombreux endroits, je pourrais envisager d’écrire un simple décorateur List qui intègre tous les éléments. Par exemple:

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

Ce n’est pas un exemple complet (ni même testé), c’est juste quelque chose pour commencer ...

9
Steven Schlansker

Pour définir un tableau de longueur variable, utilisez simplement la bibliothèque Apache commons.io.IOUtils au lieu d’attribuer une longueur manuelle, comme ceci:

byte[] b=new byte[50];

Vous pouvez transmettre votre flux d’entrée à la fonction IOUtils qui effectuera une fonction de lecture sur ce flux d’entrée, ainsi le tableau d’octets aura la longueur exacte d’octets nécessaire.

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

Le chaos..

2
Prashant

ByteArrayOutputStream permettra l'écriture dans un tableau d'octets dynamique. Toutefois, les méthodes telles que remove, replace et insert ne sont pas disponibles. Il faut extraire le tableau d'octets puis le manipuler directement.

1
Nathan

Votre meilleur pari est d'utiliser une liste de tableaux. Comme il redimensionne comme vous le remplissez.

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

1
1-----1

La solution évidente serait d'utiliser un ArrayList.

Mais c'est une mauvaise solution si vous avez besoin de performances ou si vous êtes contraint en mémoire, car il ne stocke pas réellement des octets mais des octets (c'est-à-dire des objets).

Pour toute application réelle, la réponse est simple: vous devez gérer vous-même le tableau d'octets, en utilisant des méthodes qui le font évoluer au besoin. Vous pouvez l'intégrer dans une classe spécifique si nécessaire:

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;
    }
}
1
Denys Séguret

Vous pouvez utiliser IOUtils à la pièce, comme Prashant l’a déjà dit.

Voici un petit morceau de celui-ci qui peut résoudre la tâche (vous aurez besoin de 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;

}
}
0
Jehy

Utiliser un ArrayList de n’importe quel sous-type de List

Les différentes implémentations de List peuvent vous permettre de faire différentes choses sur la liste (par exemple, une stratégie de traversée différente, des performances différentes, etc.)

0
RNJ

La capacité initiale de ArrayList est de 10. Vous pouvez le modifier à l’aide de ArrayList (5000). ArrayList double sa taille si nécessaire (il créera un nouveau tableau et copiera l’ancien dans le nouveau).

0
Andrzej Rehmann

Je Tweak légèrement les réponses des autres.

Créez une classe LargeByteArray pour gérer votre tableau. Il aura des méthodes get et set, etc., tout ce dont vous aurez besoin.

Dans les coulisses, cette classe utilisera un long pour conserver la longueur actuelle et utilisera une ArrayList pour stocker le contenu du tableau.

Je choisirais de stocker des tableaux d'octets [8192] ou d'octets [16384] dans ArrayList. Cela donnera un compromis raisonnable en termes de taille gaspillée et réduira le besoin de redimensionnement.

Vous pouvez même rendre le tableau 'sparse', c'est-à-dire n'allouer que l'entrée list.get (index/8192) s'il existe une valeur non nulle stockée dans cette zone.

Une telle structure peut vous donner beaucoup plus de stockage dans certains cas.

Une autre stratégie que vous pouvez utiliser consiste à compresser les boîtes d'octets [] après écriture et à décompresser avant lecture (utilisez un cache LRU pour la lecture), ce qui peut permettre de stocker deux fois ou plus que la mémoire vive disponible ... Bien que cela dépende de la stratégie de compression.

Après cela, vous pouvez envisager de paginer certaines boîtes sur le disque ... 

C'est aussi proche d'un tableau infini que je peux vous avoir ;-)

0
Stephen Connolly