Convierta InputStream a una matriz de bytes en Java

Respuestas:

1136

Puede usar Apache Commons IO para manejar esta y otras tareas similares.

El IOUtilstipo tiene un método estático para leer InputStreamy devolver a byte[].

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

Internamente, esto crea ay ByteArrayOutputStreamcopia los bytes a la salida, luego llama toByteArray(). Maneja archivos grandes copiando los bytes en bloques de 4KiB.

Vendedor rico
fuente
188
Por la falta de escribir 4 líneas de código, ¿cree que vale la pena importar una dependencia de terceros?
oxbow_lakes
217
Si hay una biblioteca que maneja el requisito, y se ocupa del procesamiento de archivos grandes, y está bien probado, seguramente la pregunta es ¿por qué lo escribiría yo mismo? El frasco es solamente 107KB y si tiene la necesidad de un método de ello, es probable que el uso de otros también
Rich Vendedor
242
@oxbow_lakes: Teniendo en cuenta la asombrosa cantidad de malas implementaciones de esta función que he visto en mi vida desarrollador, creo que es muy mucho la pena la dependencia externa para hacerlo bien.
Joachim Sauer
17
¿Por qué no ir y echar un vistazo a las cosas comunes de Apache como FastArrayListo sus mapas de referencia blandos y débiles y volver a decirme cuán "bien probada" es esta biblioteca? Es un montón de basura
oxbow_lakes
87
Además de Apache commons-io, echa un vistazo a la clase ByteStreams de Google Guava . InputStream is; byte[] filedata=ByteStreams.toByteArray(is);
michaelok
446

Debe leer cada byte de su InputStreamy escribirlo en unByteArrayOutputStream .

Luego puede recuperar la matriz de bytes subyacente llamando a 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();
Adamski
fuente
17
¿Qué pasa con el tamaño del byte recién creado []. ¿Por qué es 16384? ¿Cómo podría determinar el tamaño exacto correcto? Muchas gracias.
Ondrej Bozek
66
16384 es una elección bastante arbitraria, aunque tiendo a favorecer potencias de 2 para aumentar la posibilidad de que la matriz se alinee con los límites de las palabras. La respuesta de pihentagy muestra cómo puede evitar usar un búfer intermedio, sino más bien asignar una matriz del tamaño correcto. A menos que esté tratando con archivos grandes, personalmente prefiero el código anterior, que es más elegante y se puede usar para InputStreams, donde no se conoce de antemano el número de bytes a leer.
Adamski el
@Adamski ¿No es la creación de una matriz de bytes mucho más grande de lo que esperas que los datos estén en la secuencia, desperdicia la memoria?
Paul Brewczynski
@bluesm: Sí, eso es correcto. Sin embargo, en mi ejemplo, la matriz de bytes tiene solo 16 Kb y es muy pequeña para los estándares actuales. Además, por supuesto, esta memoria se liberará nuevamente después.
Adamski el
55
@Adamski Una gran cantidad de hardware de infraestructura, servidores web y componentes de la capa del sistema operativo están utilizando buffers 4K para mover datos, por lo que esa es la razón del número exacto, pero el punto principal es que obtienes tan poco aumento de rendimiento al pasar 4K que generalmente se considera un desperdicio de memoria. Supongo que esto sigue siendo cierto, ¡porque tengo un conocimiento de hace una década!
132

Utilice Java de Vanilla DataInputStreamy su readFullymétodo (existe desde al menos Java 1.4):

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

Hay algunos otros sabores de este método, pero lo uso todo el tiempo para este caso de uso.

dermoritz
fuente
45
+1 para usar las bibliotecas estándar en lugar de una dependencia de terceros. Desafortunadamente no me funciona porque no sé la longitud de la transmisión por adelantado.
Andrew Spencer
2
¿Qué es imgFile? No puede ser un InputStream, que se suponía que era la entrada de este método
Janus Troelsen
44
@janus es un "Archivo". de esta manera solo funciona si conoce la longitud del archivo o el recuento de bytes para leer.
dermoritz
55
Lo interesante, pero debe saber la longitud exacta de la (parte de) la secuencia para leer. Además, la clase DataInputStreamse usa principalmente para leer tipos primarios (Longs, Shorts, Chars ...) de una secuencia, por lo que podemos ver este uso como un mal uso de la clase.
Olivier Faucheux
17
Si ya conoce la longitud de los datos para leer de la secuencia, esto no es mejor que InputStream.read.
Recogida de Logan el
119

Si usa google guava , será tan simple como:

byte[] bytes = ByteStreams.toByteArray(inputStream);
Bertie
fuente
8
ByteStreamsestá anotado con@Beta
Kid101
47

Como siempre, Spring Framework (spring-core desde 3.2.2) tiene algo para usted:StreamUtils.copyToByteArray()

Arne Burmeister
fuente
Como la mayoría de los demás, quería evitar usar una biblioteca de terceros para algo tan simple, pero Java 9 no es una opción en este momento ... afortunadamente, ya estaba usando 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();
}
oliverkn
fuente
2
Es un ejemplo y, como tal, la brevedad está a la orden del día. También devolver nulo aquí sería la elección adecuada en algunos casos (aunque en un entorno de producción también tendría un manejo y documentación de excepción adecuados).
11
Entiendo la brevedad en un ejemplo, pero ¿por qué no hacer que el método de ejemplo arroje IOException en lugar de tragarlo y devolver un valor sin sentido?
pendor
44
Me he tomado la libertad de cambiar de 'return null' a 'throw IOException'
kritzikratzi
3
Probar con recursos no es necesario aquí, porque ByteArrayOutputStream # close () no hace nada. (ByteArrayOutputStream # flush () no es necesario y tampoco hace nada.)
Luke Hutchison
25

Solución segura (con capacidad declosetransmisión correcta):

  • Versión de Java 9+:

    final byte[] bytes;
    try (inputStream) {
        bytes = inputStream.readAllBytes();
    }
  • Versión de 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);
            }
        }
    }
  • Versión de Kotlin (cuando Java 9+ no es accesible):

    @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()
        }
    }

    Para evitar anidados usever aquí .

Mir-Ismaili
fuente
¿No significa que en algún momento tendrías el doble de memoria utilizada, porque tienes tanto el búfer como la matriz de bytes? ¿No hay una manera de enviar los bytes directamente a la matriz de bytes de salida?
Desarrollador de Android
@desarrollador de Android; Lo siento. No se la respuesta! Pero no lo creo. Creo que de esta manera (usando buffer) es una forma optimizada.
Mir-Ismaili
Lo he comprobado y lo hace, pero parece que es la única solución que puede elegir cuando no conoce el tamaño. Si ya conoce el tamaño, puede crear directamente la matriz de bytes con el tamaño dado y llenarlo. Por lo tanto, utiliza una función que obtendrá un parámetro del tamaño del byte, y si es válido, úselo para crear y llenar directamente la matriz de bytes, sin crear ningún otro objeto grande.
Desarrollador de Android
@desarrollador de Android; Gracias por tu información. Yo no los conocía.
Mir-Ismaili
19

¿Realmente necesitas la imagen como a byte[]? ¿Qué esperas exactamente en elbyte[] contenido completo de un archivo de imagen, codificado en cualquier formato en el que esté el archivo de imagen, o valores de píxeles RGB?

Otras respuestas aquí le muestran cómo leer un archivo en un byte[]. Su byte[]contendrá el contenido exacto del archivo, y que había necesidad de decodificación que hacer nada con los datos de imagen.

La API estándar de Java para leer (y escribir) imágenes es la API ImageIO, que puede encontrar en el paquete javax.imageio. Puede leer una imagen de un archivo con una sola línea de código:

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

Esto te dará un BufferedImage, no un byte[]. Para obtener los datos de la imagen, puede llamar getRaster()al BufferedImage. Esto le dará un Rasterobjeto, que tiene métodos para acceder a los datos de píxeles (tiene varios getPixel()/getPixels() métodos).

Buscar la documentación de la API para javax.imageio.ImageIO, java.awt.image.BufferedImage, java.awt.image.Rasteretc.

ImageIO admite varios formatos de imagen de forma predeterminada: JPEG, PNG, BMP, WBMP y GIF. Es posible agregar soporte para más formatos (necesitaría un complemento que implemente la interfaz del proveedor de servicios ImageIO).

Consulte también el siguiente tutorial: Trabajar con imágenes

Jesper
fuente
16

En caso de que alguien todavía esté buscando una solución sin dependencia y si tiene un archivo .

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);
harsh_v
fuente
Digamos, ¿qué pasa si la matriz de bytes es demasiado grande, lo que podría causar OOM para el montón? ¿Existe una solución similar que usará JNI para almacenar los bytes, y luego podríamos usar inputStream de los datos almacenados allí (una especie de caché temporal)?
Desarrollador de Android
14

Si no desea usar la biblioteca Apache commons-io, este fragmento se toma de la clase sun.misc.IOUtils. Es casi el doble de rápido que la implementación común con 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;
}
Kristian Kraljic
fuente
Esta es una solución un poco extraña, la longitud es un límite superior en la longitud de la matriz. Si conoce la longitud, todo lo que necesita es: byte [] salida = nuevo byte [longitud]; is.read (salida); (pero vea mi respuesta)
Luke Hutchison
@ luke-hutchison como dije, esta es la solución de sun.misc.IOUtils. En los casos más comunes, no conoce el tamaño de un InputStream por adelantado, entonces si (length == -1) length = Integer.MAX_VALUE; aplica. Esta solución funciona, incluso si la longitud dada es mayor que la longitud de InputStream.
Kristian Kraljic
@LukeHutchison Si conoce la longitud, puede manejarlo con unas pocas líneas. Si observa cada respuesta, todos se quejan de que no se conoce la longitud. Finalmente, una respuesta que es estándar, se puede usar con Java 7 Android y no requiere ninguna biblioteca externa.
Csaba Toth
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();
YulCheney
fuente
8

@ Adamski: puede evitar el búfer por completo.

Código copiado de http://www.exampledepot.com/egs/java.io/File2ByteArray.html (Sí, es muy detallado, pero necesita la mitad del tamaño de la memoria que la otra solución).

// 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;
}
pihentagy
fuente
55
Depende de saber el tamaño por adelantado.
stolsvik
2
Por supuesto, pero deberían saber el tamaño: "Quiero leer una imagen"
piratería
1
Si conoce el tamaño, Java le proporcionará el código. vea mi respuesta o google para "DataInputStream" y es el método readFully.
dermoritz
Debe agregar is.close()si offset < bytes.lengtho InputStreamno se cerrará si se produce esa excepción.
Jared Rummler
3
Entonces mejor, deberías usar 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();
Aturio
fuente
Sin embargo, por lo general, el sistema operativo ya es suficiente para que esto no sea una gran preocupación para los archivos más pequeños. No es como si el cabezal del disco duro leyera cada byte por separado (un disco duro es una placa de vidrio giratoria con información codificada magnética, un poco como ese icono extraño que usamos para guardar datos: P).
Maarten Bodewes
66
@Maarten Bodewes: la mayoría de los dispositivos tienen una especie de transferencia de bloque, por lo que no todas las lecturas () causarán un acceso real al dispositivo, pero tener una llamada al sistema operativo por byte ya es suficiente para matar el rendimiento. Si bien envolviendo la InputStreamde una BufferedInputStreamantes de que el código se reduciría el OS-llamadas y mitigar los inconvenientes de rendimiento significativamente, que el código todavía va a hacer el trabajo manual de la copia innecesaria de un tampón a otro.
Holger
4

Java 9 finalmente te dará un buen método:

InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();
Christian Ullenboom
fuente
44
¿Cuál es la diferencia entre esto y InputStram.readAllBytes()eso es de una sola línea?
Slava Semushin
2

Sé que es demasiado tarde, pero aquí creo que es una solución más limpia que es más legible ...

/**
 * 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();
}
Solución simple
fuente
44
Deberías usar try-with-resources.
Victor Stafusa
Su limpieza al final debe hacerse en un bloque finalmente en caso de errores, de lo contrario, esto podría causar una pérdida de memoria.
MGDavies
2

Java 8 way (gracias a BufferedReader y 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>);
    }
}

Tenga en cuenta que esta solución elimina el retorno de carro ('\ r') y puede ser inapropiado.

Ilya Bystrov
fuente
44
Eso es para String. OP está pidiendo byte[].
FrozenFire
No solo \reso podría ser un problema. Este método convierte los bytes en caracteres y viceversa (usando el juego de caracteres predeterminado para InputStreamReader). Todos los bytes que no sean válidos en la codificación de caracteres predeterminada (por ejemplo, -1 para UTF-8 en Linux) se dañarán, lo que podría incluso cambiar el número de bytes.
seanf
Parece que esta es una buena respuesta, pero orientada al texto. El comprador tenga cuidado.
Wheezil
1

Intenté editar la respuesta de @ numan con una solución para escribir datos basura, pero la edición fue rechazada. Si bien este breve fragmento de código no es nada brillante, no puedo ver ninguna otra respuesta mejor. Esto es lo que tiene más sentido para mí:

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

Por cierto, ByteArrayOutputStream no necesita cerrarse. try / finalmente construcciones omitidas por legibilidad

akostadinov
fuente
1

Ver la InputStream.available()documentación:

Es particularmente importante darse cuenta de que no debe usar este método para dimensionar un contenedor y asumir que puede leer la totalidad de la secuencia sin necesidad de cambiar el tamaño del contenedor. Esas personas que llaman probablemente deberían escribir todo lo que leen en un ByteArrayOutputStream y convertirlo en una matriz de bytes. Alternativamente, si está leyendo desde un archivo, File.length devuelve la longitud actual del archivo (aunque suponiendo que la longitud del archivo no puede cambiar puede ser incorrecto, la lectura de un archivo es inherentemente picante).

yichouangle
fuente
1

Envuélvalo en un DataInputStream si eso está fuera de la tabla por alguna razón, solo use leer para martillarlo hasta que le dé un -1 o el bloque completo que solicitó.

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;
}
Tatarizar
fuente
1

Estamos viendo algunos retrasos en algunas transacciones de AWS, al convertir el objeto S3 en ByteArray.

Nota: El objeto S3 es un documento PDF (el tamaño máximo es de 3 mb).

Estamos utilizando la opción # 1 (org.apache.commons.io.IOUtils) para convertir el objeto S3 a ByteArray. Hemos notado que S3 proporciona el método IOUtils incorporado para convertir el objeto S3 a ByteArray, se le solicita que confirme cuál es la mejor manera de convertir el objeto S3 a ByteArray para evitar el retraso.

Opción 1:

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

Opcion 2:

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

También avíseme si tenemos otra forma mejor de convertir el objeto s3 a bytearray

Bharathiraja S
fuente
0

El otro caso es obtener la matriz de bytes correcta a través de la secuencia, después de enviar la solicitud al servidor y esperar la respuesta.

/**
         * 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);
Torre huy
fuente
0

Estás haciendo una copia adicional si usas ByteArrayOutputStream. Si conoce la longitud de la secuencia antes de comenzar a leerla (por ejemplo, InputStream es en realidad un FileInputStream, y puede llamar a file.length () en el archivo, o InputStream es una entrada de archivo zip InputStream, y puede llamar a zipEntry. length ()), entonces es mucho mejor escribir directamente en la matriz de bytes []: usa la mitad de la memoria y ahorra tiempo.

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

Nota: la última línea anterior trata con archivos que se truncan mientras se lee la secuencia, si necesita manejar esa posibilidad, pero si el archivo se alarga mientras se lee la secuencia, los contenidos en la matriz byte [] no se alargarán para incluir el nuevo contenido del archivo, la matriz simplemente se truncará a la longitud antigua inputStreamLength .

Luke Hutchison
fuente
0

Yo uso esto.

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();
        }
    }
cchcc
fuente
2
Agregue alguna explicación con la respuesta de cómo esta respuesta ayuda a OP a solucionar el problema actual
ρяσѕρєя K
0

Esta es mi versión de copiar y pegar:

@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();
}
Daniel De León
fuente
2
Si bien este fragmento de código puede resolver la pregunta, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y que esas personas podrían no conocer los motivos de su sugerencia de código.
Ferrybig
0

Java 7 y posterior:

import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);
Antonio
fuente
20
sun.misc.IOUtilsno es "Java 7". Es una clase patentada de implementación específica que puede no estar presente en otras implementaciones de JRE y puede desaparecer sin previo aviso en una de las próximas versiones.
Holger
0

Puedes probar Cactoos :

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

Aquí hay una versión optimizada, que intenta evitar copiar bytes de datos tanto como sea posible:

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;
   }
}
Christian d'Heureuse
fuente
0

Solución en Kotlin (también funcionará en Java, por supuesto), que incluye ambos casos de cuándo conoce el tamaño o no:

    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 conoce el tamaño, le ahorra tener el doble de memoria utilizada en comparación con las otras soluciones (en un breve momento, pero aún podría ser útil). Esto se debe a que tiene que leer todo el flujo hasta el final y luego convertirlo en una matriz de bytes (similar a ArrayList que convierte en solo una matriz).

Entonces, si está en Android, por ejemplo, y tiene que manejar algunos Uri, puede intentar obtener el tamaño usando esto:

    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
    }
desarrollador de Android
fuente
-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();
}
Madhu
fuente
Cerrar y enjuagar bos es un desperdicio de clics del teclado. Cerrar el flujo de entrada es más probable que ayude. Leer un byte a la vez es ineficiente. Ver la respuesta de Numan.
akostadinov