Convertir InputStream en tableau d'octets en Java


Réponses:


1136

Vous pouvez utiliser Apache Commons IO pour gérer cela et des tâches similaires.

Le IOUtilstype a une méthode statique pour lire InputStreamet renvoyer un byte[].

InputStream is;
byte[] bytes = IOUtils.toByteArray(is);

En interne, cela crée un ByteArrayOutputStreamet copie les octets dans la sortie, puis appelle toByteArray(). Il gère les fichiers volumineux en copiant les octets dans des blocs de 4 Ko.


188
Par manque d'écriture de 4 lignes de code, vous pensez que l'importation d'une dépendance tierce vaut la peine?
oxbow_lakes

217
S'il existe une bibliothèque qui gère l'exigence, traite le traitement des fichiers volumineux et est bien testée, la question est sûrement pourquoi je l'écrirais moi-même? Le pot ne fait que 107 Ko et si vous avez besoin d'une méthode, vous en utiliserez probablement d'autres
Rich Seller

242
@oxbow_lakes: compte tenu de la quantité phénoménale de mauvaises implémentations de cette fonctionnalité que je l' ai vu dans ma vie de développeur, je pense que oui , il est très bien vaut la dépendance extérieure pour obtenir ce droit.
Joachim Sauer

17
Pourquoi ne pas aller voir les trucs communs Apache comme FastArrayListou leurs cartes de référence douces et faibles et revenir me dire à quel point cette bibliothèque est "bien testée". C'est un tas d'ordures
oxbow_lakes

87
En plus d'Apache commons-io, consultez la classe ByteStreams de Google Guava . InputStream is; byte[] filedata=ByteStreams.toByteArray(is);
michaelok

446

Vous devez lire chaque octet de votre InputStreamet l'écrire dans a ByteArrayOutputStream.

Vous pouvez ensuite récupérer le tableau d'octets sous-jacent en appelant toByteArray():

InputStream is = ...
ByteArrayOutputStream buffer = new ByteArrayOutputStream();

int nRead;
byte[] data = new byte[16384];

while ((nRead = is.read(data, 0, data.length)) != -1) {
  buffer.write(data, 0, nRead);
}

return buffer.toByteArray();

17
Qu'en est-il de la taille de l'octet nouvellement créé []. Pourquoi est-ce 16384? Comment pourrais-je déterminer la bonne taille exacte? Merci beaucoup.
Ondrej Bozek

6
16384 est un choix assez arbitraire même si j'ai tendance à privilégier les puissances de 2 pour augmenter les chances d'alignement du tableau avec les limites des mots. La réponse de pihentagy montre comment vous pouvez éviter d'utiliser un tampon intermédiaire, mais plutôt allouer un tableau de la bonne taille. Sauf si vous avez affaire à de gros fichiers, je préfère personnellement le code ci-dessus, qui est plus élégant et peut être utilisé pour InputStreams où le nombre d'octets à lire n'est pas connu à l'avance.
Adamski

@Adamski La création d'un tableau d'octets n'est-elle pas beaucoup plus importante que ce que vous attendez des données dans le flux, gaspillez-vous la mémoire?
Paul Brewczynski

@bluesm: Oui, c'est exact. Cependant, dans mon exemple, le tableau d'octets n'est que de 16 Ko et si petit par rapport aux normes d'aujourd'hui. Bien entendu, cette mémoire sera à nouveau libérée par la suite.
Adamski

5
@Adamski Beaucoup de matériel d'infrastructure, de serveurs Web et de composants de la couche OS utilisent des tampons 4K pour déplacer les données, c'est donc la raison du nombre exact, mais l'essentiel est que vous obtenez une telle amélioration des performances en passant par 4K qu'il est généralement considéré comme un gaspillage de mémoire. Je suppose que c'est toujours vrai, car c'est une connaissance vieille de dix ans que j'avais!


132

Utilisez le Java vanilla DataInputStreamet sa readFullyméthode (existe depuis au moins Java 1.4):

...
byte[] bytes = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(bytes);
...

Il existe d'autres variantes de cette méthode, mais je l'utilise tout le temps pour ce cas d'utilisation.


45
+1 pour l'utilisation des bibliothèques standard au lieu d'une dépendance tierce. Malheureusement, cela ne fonctionne pas pour moi car je ne connais pas la longueur du flux à l'avance.
Andrew Spencer

2
qu'est-ce que imgFile? Ce ne peut pas être un InputStream, qui était censé être l'entrée de cette méthode
Janus Troelsen

4
@janus c'est un "Fichier". cette façon ne fonctionne que si vous connaissez la longueur du fichier ou le nombre d'octets à lire.
dermoritz

5
Chose intéressante, mais vous devez connaître la longueur exacte du (partie du) flux à lire. De plus, la classe DataInputStreamest principalement utilisée pour lire les types primaires (Longs, Shorts, Chars ...) à partir d'un flux, nous pouvons donc voir cette utilisation comme une mauvaise utilisation de la classe.
Olivier Faucheux

17
Si vous connaissez déjà la longueur des données à lire dans le flux, ce n'est pas mieux que InputStream.read.
Ramassage Logan du

119

Si vous utilisez google goyave , ce sera aussi simple que:

byte[] bytes = ByteStreams.toByteArray(inputStream);

8
ByteStreamsest annoté avec@Beta
Kid101

47

Comme toujours, le framework Spring (Spring-core depuis 3.2.2) a quelque chose pour vous:StreamUtils.copyToByteArray()


Comme la plupart des autres, je voulais éviter d'utiliser une bibliothèque tierce pour quelque chose de si simple, mais Java 9 n'est pas une option pour le moment ... heureusement, j'utilisais déjà Spring.
scottysseus

42
public static byte[] getBytesFromInputStream(InputStream is) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream(); 
    byte[] buffer = new byte[0xFFFF];
    for (int len = is.read(buffer); len != -1; len = is.read(buffer)) { 
        os.write(buffer, 0, len);
    }
    return os.toByteArray();
}

2
C'est un exemple et à ce titre, la brièveté est à l'ordre du jour. Renvoyer également null ici serait le bon choix dans certains cas (bien que dans un environnement de production, vous auriez également une gestion et une documentation des exceptions appropriées).

11
Je comprends la brièveté dans un exemple, mais pourquoi ne pas simplement faire en sorte que l'exemple de méthode lance IOException plutôt que de l'avaler et de renvoyer une valeur vide de sens?
pendor

4
j'ai pris la liberté de passer de 'return null' à 'throw IOException'
kritzikratzi

3
Try-with-resources n'est pas nécessaire ici, car ByteArrayOutputStream # close () ne fait rien. (ByteArrayOutputStream # flush () n'est pas nécessaire et ne fait rien de trop.)
Luke Hutchison

25

Solution sûre (avec capacité decloseflux correctement):

  • Version Java 9+:

    final byte[] bytes;
    try (inputStream) {
        bytes = inputStream.readAllBytes();
    }
  • Version Java 8:

    public static byte[] readAllBytes(InputStream inputStream) throws IOException {
        final int bufLen = 4 * 0x400; // 4KB
        byte[] buf = new byte[bufLen];
        int readLen;
        IOException exception = null;
    
        try {
            try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                while ((readLen = inputStream.read(buf, 0, bufLen)) != -1)
                    outputStream.write(buf, 0, readLen);
    
                return outputStream.toByteArray();
            }
        } catch (IOException e) {
            exception = e;
            throw e;
        } finally {
            if (exception == null) inputStream.close();
            else try {
                inputStream.close();
            } catch (IOException e) {
                exception.addSuppressed(e);
            }
        }
    }
  • Version Kotlin (lorsque Java 9+ n'est pas accessible):

    @Throws(IOException::class)
    fun InputStream.readAllBytes(): ByteArray {
        val bufLen = 4 * 0x400 // 4KB
        val buf = ByteArray(bufLen)
        var readLen: Int = 0
    
        ByteArrayOutputStream().use { o ->
            this.use { i ->
                while (i.read(buf, 0, bufLen).also { readLen = it } != -1)
                    o.write(buf, 0, readLen)
            }
    
            return o.toByteArray()
        }
    }

    Pour éviter l'imbrication, usevoir ici .


Cela ne signifie-t-il pas qu'à un moment donné, vous auriez le double de la mémoire utilisée, car vous disposez à la fois du tampon et du tableau d'octets? N'y a-t-il pas un moyen d'envoyer les octets directement au tableau d'octets de sortie?
développeur Android

@androiddeveloper; Je suis désolé. Je ne connais pas la réponse! Mais je ne pense pas. Je pense que cette façon (en utilisant un tampon) est une manière optimisée.
Mir-Ismaili

J'ai vérifié et c'est le cas, mais il semble que c'est la seule solution que vous pouvez choisir lorsque vous ne connaissez pas la taille. Si vous connaissez déjà la taille, vous pouvez créer directement le tableau d'octets avec la taille donnée et le remplir. Ainsi, vous utilisez une fonction qui obtiendra un paramètre de la taille de l'octet, et si elle est valide, utilisez-la pour créer et remplir directement le tableau d'octets, sans créer d'autre grand objet.
développeur Android

@androiddeveloper; Merci pour ton information. Je ne les connaissais pas.
Mir-Ismaili

19

Avez-vous vraiment besoin de l'image en tant que byte[]? Qu'attendez-vous exactement dans le byte[]- le contenu complet d'un fichier image, encodé dans le format dans lequel le fichier image est, ou les valeurs de pixels RVB?

D'autres réponses ici vous montrent comment lire un fichier dans un fichier byte[]. Votre byte[]contiendra le contenu exact du fichier et vous devrez le décoder pour faire quoi que ce soit avec les données d'image.

L'API standard de Java pour la lecture (et l'écriture) d'images est l'API ImageIO, que vous pouvez trouver dans le package javax.imageio. Vous pouvez lire une image à partir d'un fichier avec une seule ligne de code:

BufferedImage image = ImageIO.read(new File("image.jpg"));

Cela vous donnera un BufferedImage, pas un byte[]. Pour accéder aux données d'image, vous pouvez appeler getRaster()le BufferedImage. Cela vous donnera un Rasterobjet, qui a des méthodes pour accéder aux données de pixel (il en a plusieurs getPixel()/ getPixels()méthodes).

Lookup la documentation de l' API pour javax.imageio.ImageIO, java.awt.image.BufferedImage, java.awt.image.Rasteretc.

ImageIO prend en charge un certain nombre de formats d'image par défaut: JPEG, PNG, BMP, WBMP et GIF. Il est possible d'ajouter la prise en charge de plusieurs formats (vous auriez besoin d'un plug-in qui implémente l'interface du fournisseur de services ImageIO).

Voir également le didacticiel suivant: Utilisation des images


16

Dans le cas où quelqu'un est toujours à la recherche d'une solution sans dépendance et si vous avez un fichier .

1) DataInputStream

 byte[] data = new byte[(int) file.length()];
 DataInputStream dis = new DataInputStream(new FileInputStream(file));
 dis.readFully(data);
 dis.close();

2) ByteArrayOutputStream

 InputStream is = new FileInputStream(file);
 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
 int nRead;
 byte[] data = new byte[(int) file.length()];
 while ((nRead = is.read(data, 0, data.length)) != -1) {
     buffer.write(data, 0, nRead);
 }

3) RandomAccessFile

 RandomAccessFile raf = new RandomAccessFile(file, "r");
 byte[] data = new byte[(int) raf.length()];
 raf.readFully(data);

Par exemple, que se passe-t-il si le tableau d'octets est trop grand, ce qui pourrait provoquer un MOO pour le tas? Existe-t-il une solution similaire qui utilisera JNI pour stocker les octets, et plus tard, nous pourrons utiliser inputStream à partir des données qui y sont stockées (sorte de cache temporaire)?
développeur Android

14

Si vous ne souhaitez pas utiliser la bibliothèque Apache commons-io, cet extrait est extrait de la classe sun.misc.IOUtils. C'est presque deux fois plus rapide que l'implémentation courante utilisant ByteBuffers:

public static byte[] readFully(InputStream is, int length, boolean readAll)
        throws IOException {
    byte[] output = {};
    if (length == -1) length = Integer.MAX_VALUE;
    int pos = 0;
    while (pos < length) {
        int bytesToRead;
        if (pos >= output.length) { // Only expand when there's no room
            bytesToRead = Math.min(length - pos, output.length + 1024);
            if (output.length < pos + bytesToRead) {
                output = Arrays.copyOf(output, pos + bytesToRead);
            }
        } else {
            bytesToRead = output.length - pos;
        }
        int cc = is.read(output, pos, bytesToRead);
        if (cc < 0) {
            if (readAll && length != Integer.MAX_VALUE) {
                throw new EOFException("Detect premature EOF");
            } else {
                if (output.length != pos) {
                    output = Arrays.copyOf(output, pos);
                }
                break;
            }
        }
        pos += cc;
    }
    return output;
}

C'est un peu une solution bizarre, la longueur est une limite supérieure sur la longueur du tableau. Si vous connaissez la longueur, tout ce dont vous avez besoin est: octet [] sortie = nouvel octet [longueur]; is.read (sortie); (mais voir ma réponse)
Luke Hutchison

@ luke-hutchison comme je l'ai dit, c'est la solution de sun.misc.IOUtils. Dans les cas les plus courants, vous ne connaissez pas la taille d'un InputStream à l'avance, donc si (length == -1) length = Integer.MAX_VALUE; s'applique. Cette solution fonctionne, même si la longueur donnée est supérieure à la longueur de InputStream.
Kristian Kraljic

@LukeHutchison Si vous connaissez la longueur, vous pouvez le gérer avec quelques lignes. Si vous regardez chaque réponse, tout le monde se plaint que la longueur n'est pas connue. Enfin une réponse qui est standard, peut être utilisée avec Java 7 Android, et ne nécessite aucune bibliothèque externe.
Csaba Toth du

11
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while (true) {
    int r = in.read(buffer);
    if (r == -1) break;
    out.write(buffer, 0, r);
}

byte[] ret = out.toByteArray();

8

@Adamski: Vous pouvez éviter complètement le tampon.

Code copié depuis http://www.exampledepot.com/egs/java.io/File2ByteArray.html (Oui, il est très verbeux, mais nécessite la moitié de la taille de la mémoire comme l'autre solution.)

// Returns the contents of the file in a byte array.
public static byte[] getBytesFromFile(File file) throws IOException {
    InputStream is = new FileInputStream(file);

    // Get the size of the file
    long length = file.length();

    // You cannot create an array using a long type.
    // It needs to be an int type.
    // Before converting to an int type, check
    // to ensure that file is not larger than Integer.MAX_VALUE.
    if (length > Integer.MAX_VALUE) {
        // File is too large
    }

    // Create the byte array to hold the data
    byte[] bytes = new byte[(int)length];

    // Read in the bytes
    int offset = 0;
    int numRead = 0;
    while (offset < bytes.length
           && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
        offset += numRead;
    }

    // Ensure all the bytes have been read in
    if (offset < bytes.length) {
        throw new IOException("Could not completely read file "+file.getName());
    }

    // Close the input stream and return bytes
    is.close();
    return bytes;
}

5
Dépend de connaître la taille à l'avance.
stolsvik

2
Bien sûr, mais ils devraient connaître la taille: "Je veux lire une image"
pihentagy

1
si vous connaissez la taille, alors java fournit le code pour vous. voir ma réponse ou google pour "DataInputStream" et c'est la méthode readFully.
dermoritz

Vous devez ajouter is.close()si offset < bytes.lengthou InputStreamne sera pas fermé si cette exception est levée.
Jared Rummler

3
Mieux encore, vous devriez utiliser try-with-resources
pihentagy

8
Input Stream is ...
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int next = in.read();
while (next > -1) {
    bos.write(next);
    next = in.read();
}
bos.flush();
byte[] result = bos.toByteArray();
bos.close();

Cependant, le système d'exploitation a déjà suffisamment de tampons pour que cela ne soit pas un gros problème pour les fichiers plus petits. Ce n'est pas comme si la tête du disque dur lisait chaque octet séparément (un disque dur est une plaque de verre tournante avec des informations codées magnétiques dessus, un peu comme cette icône bizarre que nous utilisons pour enregistrer les données: P).
Maarten Bodewes

6
@Maarten Bodewes: la plupart des appareils ont une sorte de transfert de bloc, donc pas chaque lecture () provoquera un accès réel à l'appareil, mais avoir un appel OS par octet est déjà suffisant pour tuer les performances. Bien que l'encapsulation InputStreamdans un BufferedInputStreamavant ce code réduise les appels du système d'exploitation et atténue considérablement les inconvénients de performances, ce code effectuera toujours un travail de copie manuelle inutile d'un tampon à un autre.
Holger

4

Java 9 vous donnera enfin une belle méthode:

InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();

4
Quelle est la différence entre ceci et ce InputStram.readAllBytes()qui est à une ligne?
Slava Semushin

2

Je sais qu'il est trop tard mais ici je pense que c'est une solution plus propre et plus lisible ...

/**
 * method converts {@link InputStream} Object into byte[] array.
 * 
 * @param stream the {@link InputStream} Object.
 * @return the byte[] array representation of received {@link InputStream} Object.
 * @throws IOException if an error occurs.
 */
public static byte[] streamToByteArray(InputStream stream) throws IOException {

    byte[] buffer = new byte[1024];
    ByteArrayOutputStream os = new ByteArrayOutputStream();

    int line = 0;
    // read bytes from stream, and store them in buffer
    while ((line = stream.read(buffer)) != -1) {
        // Writes bytes from byte array (buffer) into output stream.
        os.write(buffer, 0, line);
    }
    stream.close();
    os.flush();
    os.close();
    return os.toByteArray();
}

4
Vous devez utiliser try-with-resources.
Victor Stafusa

Votre rangement à la fin doit être fait dans un bloc enfin en cas d'erreurs, sinon cela pourrait provoquer une fuite de mémoire.
MGDavies

2

Java 8 way (merci à BufferedReader et Adam Bien )

private static byte[] readFully(InputStream input) throws IOException {
    try (BufferedReader buffer = new BufferedReader(new InputStreamReader(input))) {
        return buffer.lines().collect(Collectors.joining("\n")).getBytes(<charset_can_be_specified>);
    }
}

Notez que cette solution efface le retour chariot ('\ r') et peut être inappropriée.


4
C'est pour ça String. OP demande byte[].
FrozenFire

Ce n'est pas seulement \rque cela pourrait être un problème. Cette méthode convertit les octets en caractères et inversement (en utilisant le jeu de caractères par défaut pour InputStreamReader). Tous les octets qui ne sont pas valides dans le codage de caractères par défaut (disons -1 pour UTF-8 sous Linux) seront corrompus, ce qui pourrait même changer le nombre d'octets.
seanf

On dirait que c'est une bonne réponse, mais orientée texte. Méfiez-vous de l'acheteur.
Wheezil

1

J'ai essayé de modifier la réponse de @ numan avec un correctif pour écrire des données de poubelle, mais la modification a été rejetée. Bien que ce court morceau de code ne soit rien de brillant, je ne vois pas d'autre meilleure réponse. Voici ce qui me semble le plus logique:

ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024]; // you can configure the buffer size
int length;

while ((length = in.read(buffer)) != -1) out.write(buffer, 0, length); //copy streams
in.close(); // call this in a finally block

byte[] result = out.toByteArray();

btw ByteArrayOutputStream n'a pas besoin d'être fermé. essayez / finalement les constructions omises pour la lisibilité


1

Consultez la InputStream.available()documentation:

Il est particulièrement important de réaliser que vous ne devez pas utiliser cette méthode pour dimensionner un conteneur et supposer que vous pouvez lire l'intégralité du flux sans avoir besoin de redimensionner le conteneur. Ces appelants devraient probablement écrire tout ce qu'ils lisent dans un ByteArrayOutputStream et le convertir en un tableau d'octets. Alternativement, si vous lisez un fichier, File.length renvoie la longueur actuelle du fichier (bien que supposer que la longueur du fichier ne puisse pas changer peut être incorrect, la lecture d'un fichier est intrinsèquement racée).


1

Enveloppez-le dans un DataInputStream si cela est hors de la table pour une raison quelconque, utilisez simplement read pour marteler dessus jusqu'à ce qu'il vous donne un -1 ou le bloc entier que vous avez demandé.

public int readFully(InputStream in, byte[] data) throws IOException {
    int offset = 0;
    int bytesRead;
    boolean read = false;
    while ((bytesRead = in.read(data, offset, data.length - offset)) != -1) {
        read = true;
        offset += bytesRead;
        if (offset >= data.length) {
            break;
        }
    }
    return (read) ? offset : -1;
}

1

Nous constatons un certain retard pour quelques transactions AWS, lors de la conversion de l'objet S3 en ByteArray.

Remarque: l'objet S3 est un document PDF (la taille maximale est de 3 Mo).

Nous utilisons l'option # 1 (org.apache.commons.io.IOUtils) pour convertir l'objet S3 en ByteArray. Nous avons remarqué que S3 fournit la méthode IOUtils inbuild pour convertir l'objet S3 en ByteArray, nous vous demandons de confirmer quelle est la meilleure façon de convertir l'objet S3 en ByteArray pour éviter le retard.

Option 1:

import org.apache.commons.io.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);

Option 2:

import com.amazonaws.util.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);

Faites-moi également savoir si nous avons une autre meilleure façon de convertir l'objet s3 en bytearray


0

L'autre cas pour obtenir un tableau d'octets correct via le flux, après l'envoi de la demande au serveur et l'attente de la réponse.

/**
         * Begin setup TCP connection to PC app
         * to open integrate connection between mobile app and pc app (or mobile app)
         */
        mSocket = new Socket(IP, port);
       // mSocket.setSoTimeout(30000);

        DataOutputStream mDos = new DataOutputStream(mSocket.getOutputStream());

        String str = "MobileRequest#" + params[0] + "#<EOF>";

        mDos.write(str.getBytes());

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        /* Since data are accepted as byte, all of them will be collected in the
        following byte array which initialised with accepted data length. */
        DataInputStream mDis = new DataInputStream(mSocket.getInputStream());
        byte[] data = new byte[mDis.available()];

        // Collecting data into byte array
        for (int i = 0; i < data.length; i++)
            data[i] = mDis.readByte();

        // Converting collected data in byte array into String.
        String RESPONSE = new String(data);

0

Vous faites une copie supplémentaire si vous utilisez ByteArrayOutputStream. Si vous connaissez la longueur du flux avant de commencer à le lire (par exemple, InputStream est en fait un FileInputStream, et vous pouvez appeler file.length () sur le fichier, ou InputStream est une entrée de fichier zip InputStream, et vous pouvez appeler zipEntry. length ()), il est alors préférable d'écrire directement dans le tableau d'octets [] - il utilise la moitié de la mémoire et fait gagner du temps.

// Read the file contents into a byte[] array
byte[] buf = new byte[inputStreamLength];
int bytesRead = Math.max(0, inputStream.read(buf));

// If needed: for safety, truncate the array if the file may somehow get
// truncated during the read operation
byte[] contents = bytesRead == inputStreamLength ? buf
                  : Arrays.copyOf(buf, bytesRead);

NB la dernière ligne ci-dessus traite des fichiers qui sont tronqués pendant la lecture du flux, si vous avez besoin de gérer cette possibilité, mais si le fichier s'allonge pendant la lecture du flux, le contenu du tableau d'octets [] ne sera pas allongé pour inclure le nouveau contenu du fichier, le tableau sera simplement tronqué à l'ancienne longueur inputStreamLength .


0

J'utilise ça.

public static byte[] toByteArray(InputStream is) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        try {
            byte[] b = new byte[4096];
            int n = 0;
            while ((n = is.read(b)) != -1) {
                output.write(b, 0, n);
            }
            return output.toByteArray();
        } finally {
            output.close();
        }
    }

2
Ajoutez une explication avec la réponse pour savoir comment cette réponse aide OP à résoudre le problème actuel
ρяσѕρєя K

0

Voici ma version copier-coller:

@SuppressWarnings("empty-statement")
public static byte[] inputStreamToByte(InputStream is) throws IOException {
    if (is == null) {
        return null;
    }
    // Define a size if you have an idea of it.
    ByteArrayOutputStream r = new ByteArrayOutputStream(2048);
    byte[] read = new byte[512]; // Your buffer size.
    for (int i; -1 != (i = is.read(read)); r.write(read, 0, i));
    is.close();
    return r.toByteArray();
}

2
Bien que cet extrait de code puisse résoudre la question, y compris une explication aide vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondrez à la question pour les lecteurs à l'avenir, et ces personnes pourraient ne pas connaître les raisons de votre suggestion de code.
Ferrybig

0

Java 7 et versions ultérieures:

import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);

20
sun.misc.IOUtilsn'est pas «Java 7». Il s'agit d'une classe propriétaire spécifique à l'implémentation qui peut ne pas être présente dans d'autres implémentations JRE et peut disparaître sans avertissement dans l'une des prochaines versions.
Holger


0

Voici une version optimisée, qui essaie d'éviter autant que possible de copier des octets de données:

private static byte[] loadStream (InputStream stream) throws IOException {
   int available = stream.available();
   int expectedSize = available > 0 ? available : -1;
   return loadStream(stream, expectedSize);
}

private static byte[] loadStream (InputStream stream, int expectedSize) throws IOException {
   int basicBufferSize = 0x4000;
   int initialBufferSize = (expectedSize >= 0) ? expectedSize : basicBufferSize;
   byte[] buf = new byte[initialBufferSize];
   int pos = 0;
   while (true) {
      if (pos == buf.length) {
         int readAhead = -1;
         if (pos == expectedSize) {
            readAhead = stream.read();       // test whether EOF is at expectedSize
            if (readAhead == -1) {
               return buf;
            }
         }
         int newBufferSize = Math.max(2 * buf.length, basicBufferSize);
         buf = Arrays.copyOf(buf, newBufferSize);
         if (readAhead != -1) {
            buf[pos++] = (byte)readAhead;
         }
      }
      int len = stream.read(buf, pos, buf.length - pos);
      if (len < 0) {
         return Arrays.copyOf(buf, pos);
      }
      pos += len;
   }
}

0

Solution dans Kotlin (fonctionnera également en Java, bien sûr), qui comprend les deux cas où vous connaissez la taille ou non:

    fun InputStream.readBytesWithSize(size: Long): ByteArray? {
        return when {
            size < 0L -> this.readBytes()
            size == 0L -> ByteArray(0)
            size > Int.MAX_VALUE -> null
            else -> {
                val sizeInt = size.toInt()
                val result = ByteArray(sizeInt)
                readBytesIntoByteArray(result, sizeInt)
                result
            }
        }
    }

    fun InputStream.readBytesIntoByteArray(byteArray: ByteArray,bytesToRead:Int=byteArray.size) {
        var offset = 0
        while (true) {
            val read = this.read(byteArray, offset, bytesToRead - offset)
            if (read == -1)
                break
            offset += read
            if (offset >= bytesToRead)
                break
        }
    }

Si vous connaissez la taille, cela vous évite d'avoir le double de la mémoire utilisée par rapport aux autres solutions (dans un bref instant, mais pourrait tout de même être utile). C'est parce que vous devez lire l'intégralité du flux à la fin, puis le convertir en un tableau d'octets (similaire à ArrayList que vous convertissez en un simple tableau).

Donc, si vous êtes sur Android, par exemple, et que vous avez un Uri à gérer, vous pouvez essayer d'obtenir la taille en utilisant ceci:

    fun getStreamLengthFromUri(context: Context, uri: Uri): Long {
        context.contentResolver.query(uri, arrayOf(MediaStore.MediaColumns.SIZE), null, null, null)?.use {
            if (!it.moveToNext())
                return@use
            val fileSize = it.getLong(it.getColumnIndex(MediaStore.MediaColumns.SIZE))
            if (fileSize > 0)
                return fileSize
        }
        //if you wish, you can also get the file-path from the uri here, and then try to get its size, using this: https://stackoverflow.com/a/61835665/878126
        FileUtilEx.getFilePathFromUri(context, uri, false)?.use {
            val file = it.file
            val fileSize = file.length()
            if (fileSize > 0)
                return fileSize
        }
        context.contentResolver.openInputStream(uri)?.use { inputStream ->
            if (inputStream is FileInputStream)
                return inputStream.channel.size()
            else {
                var bytesCount = 0L
                while (true) {
                    val available = inputStream.available()
                    if (available == 0)
                        break
                    val skip = inputStream.skip(available.toLong())
                    if (skip < 0)
                        break
                    bytesCount += skip
                }
                if (bytesCount > 0L)
                    return bytesCount
            }
        }
        return -1L
    }

-1
/*InputStream class_InputStream = null;
I am reading class from DB 
class_InputStream = rs.getBinaryStream(1);
Your Input stream could be from any source
*/
int thisLine;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((thisLine = class_InputStream.read()) != -1) {
    bos.write(thisLine);
}
bos.flush();
byte [] yourBytes = bos.toByteArray();

/*Don't forget in the finally block to close ByteArrayOutputStream & InputStream
 In my case the IS is from resultset so just closing the rs will do it*/

if (bos != null){
    bos.close();
}

Fermer et rincer les bos est un gaspillage de clics sur le clavier. La fermeture du flux d'entrée est plus susceptible de vous aider. La lecture d'un octet à la fois est inefficace. Voir la réponse de numan.
akostadinov
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.