Respuestas:
Puede usar Apache Commons IO para manejar esta y otras tareas similares.
El IOUtils
tipo tiene un método estático para leer InputStream
y devolver a byte[]
.
InputStream is;
byte[] bytes = IOUtils.toByteArray(is);
Internamente, esto crea ay ByteArrayOutputStream
copia los bytes a la salida, luego llama toByteArray()
. Maneja archivos grandes copiando los bytes en bloques de 4KiB.
FastArrayList
o 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
InputStream is;
byte[] filedata=ByteStreams.toByteArray(is);
Debe leer cada byte de su InputStream
y 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();
Finalmente, después de veinte años, hay una solución simple sin la necesidad de una biblioteca de terceros, gracias a Java 9 :
InputStream is;
…
byte[] array = is.readAllBytes();
Tenga en cuenta también los métodos de conveniencia readNBytes(byte[] b, int off, int len)
y transferTo(OutputStream)
abordar las necesidades recurrentes.
Utilice Java de Vanilla DataInputStream
y su readFully
mé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.
DataInputStream
se 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.
InputStream.read
.
Si usa google guava , será tan simple como:
byte[] bytes = ByteStreams.toByteArray(inputStream);
ByteStreams
está anotado con@Beta
Como siempre, Spring Framework (spring-core desde 3.2.2) tiene algo para usted:StreamUtils.copyToByteArray()
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();
}
Solución segura (con capacidad declose
transmisió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 use
ver aquí .
¿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 Raster
objeto, 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.Raster
etc.
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
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);
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;
}
@ 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;
}
is.close()
si offset < bytes.length
o InputStream
no se cerrará si se produce esa excepción.
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();
InputStream
de una BufferedInputStream
antes 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.
Java 9 finalmente te dará un buen método:
InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();
InputStram.readAllBytes()
eso es de una sola línea?
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();
}
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.
String
. OP está pidiendo byte[]
.
\r
eso 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.
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
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).
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;
}
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
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);
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 .
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();
}
}
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();
}
Java 7 y posterior:
import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);
sun.misc.IOUtils
no 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.
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;
}
}
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
}
/*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();
}