web-dev-qa-db-fra.com

Convertir InputStream en tableau d'octets en Java

Comment lire une InputStream entière dans un tableau d'octets?

750
JGC

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

Le type IOUtils a une méthode statique pour lire une InputStream et renvoyer un byte[].

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

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

1019
Rich Seller

Vous devez lire chaque octet de votre InputStream et l'écrire dans un ByteArrayOutputStream. Vous pouvez ensuite récupérer le tableau d'octets sous-jacent en appelant toByteArray(); par exemple.

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();
416
Adamski

Enfin, après vingt ans, il existe une solution simple sans recourir à une bibliothèque tierce, grâce à Java 9 :

InputStream is;
…
byte[] array = is.readAllBytes();

Notez également les méthodes pratiques readNBytes(byte[] b, int off, int len) et transferTo(OutputStream) pour répondre aux besoins récurrents.

230
Holger

Utilisez la variable DataInputStream de Vanilla Java et sa méthode readFully (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.

113
dermoritz

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

byte[] bytes = ByteStreams.toByteArray(inputStream);
112
bertie
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();
}
37
oliverkn

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

34
Arne Burmeister

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

D'autres réponses ici vous montrent comment lire un fichier dans un byte[]. Votre byte[] contiendra le contenu exact du fichier, et vous devrez le décoder pour pouvoir utiliser 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 trouverez 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 une BufferedImage, pas un byte[]. Pour obtenir les données d'image, vous pouvez appeler getRaster() à la BufferedImage. Cela vous donnera un objet Raster, qui a des méthodes pour accéder aux données de pixels (il a plusieurs méthodes getPixel()/getPixels()).

Recherchez dans la documentation de l'API javax.imageio.ImageIO, Java.awt.image.BufferedImage, Java.awt.image.Raster etc.

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 un support pour plus de formats (vous aurez besoin d'un plug-in qui implémente l'interface du fournisseur de service ImageIO).

Voir aussi le tutoriel suivant: Travailler avec des images

20
Jesper

Si vous ne souhaitez pas utiliser la bibliothèque Apache commons-io, cet extrait de code est extrait de la classe Sun.misc.IOUtils. C'est presque deux fois plus vite 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;
}
14
Kristian Kraljic

Dans le cas où quelqu'un cherche toujours 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);
12
harsh_v
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();
9
YulCheney

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

Code copié à partir de http://www.exampledepot.com/egs/Java.io/File2ByteArray.html (Oui, il est très détaillé, mais nécessite la moitié de la mémoire requise.

// 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;
}
8
pihentagy
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();
8
Aturio

Safe solution (avec la capacité de close flux 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);
            }
        }
    }
    
  • _ {Kotlin} _ version (compatible avec Java ≤8):

    @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 les use imbriqués, voir ici .

4
Mir-Ismaili

Java 9 vous donnera enfin une méthode de Nice:

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

Je sais que c'est trop tard, mais je pense qu'il s'agit d'une solution plus propre, 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();
}
2
Simple-Solution

Java 7 et versions ultérieures:

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

Java 8 way (grâce à 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é.

1
Ilya Bystrov

Voir la documentation InputStream.available():

Il est particulièrement important de réaliser que vous ne devez pas utiliser ceci 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 devrait probablement écrire tout ce qu’ils ont lu dans un ByteArrayOutputStream et convertir cela en un tableau d'octets. Alternativement, si vous lisez à partir d'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, lire un fichier est intrinsèquement racé).

1
yichouangle

J'ai essayé de modifier la réponse de @ numan avec un correctif pour écrire des données erronées, mais cette modification a été rejetée. Bien que ce petit morceau de code n'ait rien de brillant, je ne vois pas de meilleure réponse. Voici ce qui a le plus de sens pour moi:

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é. try/finally construit omis pour la lisibilité

1
akostadinov

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

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

Nous utilisons l'option n ° 1 (org.Apache.commons.io.IOUtils) pour convertir l'objet S3 en ByteArray. Nous avons remarqué que S3 fournissait la méthode inbuild IOUtils pour convertir l'objet S3 en ByteArray. Nous vous demandons de confirmer le meilleur moyen de convertir l'objet S3 en ByteArray afin d'éviter le délai.

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

Dites-moi aussi si nous avons un autre meilleur moyen de convertir l'objet s3 en bytearray

0
Bharathiraja S

Vous pouvez essayer Cactoos :

byte[] array = new BytesOf(stream).bytes();
0
yegor256

Enveloppez-le dans un DataInputStream si, pour une raison quelconque, il n’est pas disponible, utilisez simplement read pour le marteler jusqu’à obtenir un -1 ou le bloc entier 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;
}
0
Tatarize

Je l'utilise.

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();
        }
    }
0
cchcc

L'autre cas consiste à obtenir le 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
Huy Tower

Ceci est 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();
}
0
Daniel De León

Voici une version optimisée, qui évite autant que possible de copier les 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

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 de loin préférable d’écrire directement dans le tableau byte [] - 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);

N.B. la dernière ligne ci-dessus concerne les fichiers tronqués pendant la lecture du flux, si vous devez gérer cette possibilité, mais si le fichier devient plus longtemps pendant la lecture du flux, le contenu du tableau byte [] sera affiché. pas être allongé pour inclure le nouveau contenu du fichier, le tableau sera simplement tronqué à l’ancienne longueur inputStreamLength .

0
Luke Hutchison