110 votes

Déterminer la taille d'un InputStream

Ma situation actuelle est la suivante : je dois lire un fichier et placer le contenu dans InputStream. Ensuite, je dois placer le contenu de InputStream dans un tableau de bytes, ce qui nécessite (autant que je sache) la taille de InputStream. Des idées ?

Comme demandé, je vais montrer le flux d'entrée que je crée à partir d'un fichier téléchargé

InputStream uploadedStream = null;
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
java.util.List items = upload.parseRequest(request);      
java.util.Iterator iter = items.iterator();

while (iter.hasNext()) {
    FileItem item = (FileItem) iter.next();
    if (!item.isFormField()) {
        uploadedStream = item.getInputStream();
        //CHANGE uploadedStreambyte = item.get()
    }
}

La requête est un objet HttpServletRequest, qui est similaire au FileItemFactory et ServletFileUpload issus du paquet Apache Commons FileUpload.

6voto

Samuel Points 5878

La fonction ci-dessous devrait fonctionner avec n'importe quel InputStream. Comme d'autres réponses l'ont suggéré, il n'est pas possible de trouver fiablement la longueur d'un InputStream sans le lire complètement, mais contrairement à d'autres réponses, vous ne devriez pas essayer de conserver l'intégralité du flux en mémoire en le lisant dans un ByteArrayOutputStream, et il n'y a aucune raison de le faire. Au lieu de lire le flux, vous devriez idéalement vous fier à d'autres API pour les tailles des flux, par exemple en obtenant la taille d'un fichier en utilisant l'API File.

public static int length(InputStream inputStream, int chunkSize) throws IOException {
    byte[] buffer = new byte[chunkSize];
    int chunkBytesRead = 0;
    int length = 0;
    while((chunkBytesRead = inputStream.read(buffer)) != -1) {
        length += chunkBytesRead;
    }
    return length;
}

Choisissez une valeur raisonnable pour chunkSize adaptée au type de InputStream. Par exemple, lors de la lecture à partir du disque, il ne serait pas efficace d'avoir une valeur trop petite pour chunkSize.

4voto

Gnanam R Points 66

Vous pouvez obtenir la taille de InputStream en utilisant getBytes(inputStream) de Utils.java. Veuillez consulter le lien suivant :

Obtenir des octets à partir de l'InputStream

2voto

Lorsque vous travaillez explicitement avec un ByteArrayInputStream, contrairement à certains commentaires sur cette page, vous pouvez utiliser la fonction .available() pour obtenir la taille. Il suffit de le faire avant de commencer à le lire.

D'après la documentation de Java:

Renvoie le nombre d'octets restants pouvant être lus (ou ignorés) à partir de ce flux d'entrée. La valeur renvoyée est count - pos, qui est le nombre d'octets restant à lire dans le tampon d'entrée.

[https://docs.oracle.com/javase/7/docs/api/java/io/ByteArrayInputStream.html#available()](https://docs.oracle.com/javase/7/docs/api/java/io/ByteArrayInputStream.html#available())

2voto

Travis Parks Points 1426

Si vous savez que votre InputStream est un FileInputStream ou un ByteArrayInputStream, vous pouvez utiliser un peu de réflexion pour obtenir la taille du flux sans lire l'intégralité du contenu. Voici un exemple de méthode :

static long getInputLength(InputStream inputStream) {
    try {
        if (inputStream instanceof FilterInputStream) {
            FilterInputStream filtered = (FilterInputStream)inputStream;
            Field field = FilterInputStream.class.getDeclaredField("in");
            field.setAccessible(true);
            InputStream internal = (InputStream) field.get(filtered);
            return getInputLength(internal);
        } else if (inputStream instanceof ByteArrayInputStream) {
            ByteArrayInputStream wrapper = (ByteArrayInputStream)inputStream;
            Field field = ByteArrayInputStream.class.getDeclaredField("buf");
            field.setAccessible(true);
            byte[] buffer = (byte[])field.get(wrapper);
            return buffer.length;
        } else if (inputStream instanceof FileInputStream) {
            FileInputStream fileStream = (FileInputStream)inputStream;
            return fileStream.getChannel().size();
        }
    } catch (NoSuchFieldException | IllegalAccessException | IOException exception) {
        // Ignore all errors and just return -1.
    }
    return -1;
}

Cela pourrait être étendu pour prendre en charge des flux d'entrée supplémentaires, j'en suis sûr.

2voto

Darthenius Points 1828

Si vous devez diffuser les données vers un autre objet qui ne vous permet pas de déterminer directement la taille (par exemple javax.imageio.ImageIO), vous pouvez envelopper votre InputStream dans un CountingInputStream (Apache Commons IO), puis lire la taille :

CountingInputStream countingInputStream = new CountingInputStream(inputStream);
// ... traiter tout le flux ...
int size = countingInputStream.getCount();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X