Risposte:
È possibile utilizzare Apache Commons IO per gestire questo e altri compiti simili.
Il IOUtils
tipo ha un metodo statico per leggere an InputStream
e restituire a byte[]
.
InputStream is;
byte[] bytes = IOUtils.toByteArray(is);
Internamente questo crea un ByteArrayOutputStream
e copia i byte nell'output, quindi chiama toByteArray()
. Gestisce file di grandi dimensioni copiando i byte in blocchi di 4KiB.
FastArrayList
o alle loro mappe di riferimento deboli e deboli e tornare a dirmi quanto è "ben collaudata" questa libreria. È un mucchio di immondizia
InputStream is;
byte[] filedata=ByteStreams.toByteArray(is);
Devi leggere ogni byte dal tuo InputStream
e scriverlo in a ByteArrayOutputStream
.
È quindi possibile recuperare l'array di byte sottostante chiamando 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, dopo vent'anni, esiste una soluzione semplice senza la necessità di una libreria di terze parti, grazie a Java 9 :
InputStream is;
…
byte[] array = is.readAllBytes();
Nota anche i metodi di convenienza readNBytes(byte[] b, int off, int len)
e le transferTo(OutputStream)
esigenze ricorrenti.
Usa vanilla Java DataInputStream
e il suo readFully
metodo (esiste almeno da Java 1.4):
...
byte[] bytes = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(bytes);
...
Esistono altri aspetti di questo metodo, ma lo uso sempre per questo caso d'uso.
DataInputStream
viene utilizzata principalmente per leggere i tipi primari (Long, Shorts, Char ...) da un flusso, quindi possiamo vedere questo utilizzo come un uso improprio della classe.
InputStream.read
.
Se ti capita di usare google guava , sarà semplice come:
byte[] bytes = ByteStreams.toByteArray(inputStream);
ByteStreams
è annotato con@Beta
Come sempre, anche il framework Spring (spring-core dal 3.2.2) ha qualcosa per te: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();
}
Soluzione sicura (con capacità diclose
streaming correttamente):
Versione Java 9+:
final byte[] bytes;
try (inputStream) {
bytes = inputStream.readAllBytes();
}
Versione 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);
}
}
}
Versione di Kotlin (quando Java 9+ non è accessibile):
@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()
}
}
Per evitare nidificati use
vedi qui .
Hai davvero bisogno dell'immagine come byte[]
? Cosa ti aspetti esattamente nelbyte[]
: il contenuto completo di un file di immagine, codificato in qualsiasi formato in cui si trova il file di immagine, o valori di pixel RGB?
Altre risposte qui mostrano come leggere un file in a byte[]
. Il tuo byte[]
conterrà il contenuto esatto del file, e avresti bisogno di decodifica che per fare qualsiasi cosa con i dati dell'immagine.
L'API standard di Java per la lettura (e la scrittura) di immagini è l'API ImageIO, che puoi trovare nel pacchetto javax.imageio
. Puoi leggere un'immagine da un file con una sola riga di codice:
BufferedImage image = ImageIO.read(new File("image.jpg"));
Questo ti darà un BufferedImage
, non un byte[]
. Per ottenere i dati dell'immagine, è possibile chiamare getRaster()
il BufferedImage
. Questo ti darà un Raster
oggetto, che ha metodi per accedere ai dati pixel (ha diversi getPixel()
/ getPixels()
metodi).
Occhiata la documentazione API per javax.imageio.ImageIO
, java.awt.image.BufferedImage
, java.awt.image.Raster
etc.
ImageIO supporta una serie di formati di immagine per impostazione predefinita: JPEG, PNG, BMP, WBMP e GIF. È possibile aggiungere supporto per più formati (sarebbe necessario un plug-in che implementa l'interfaccia del provider di servizi ImageIO).
Vedi anche il seguente tutorial: Lavorare con le immagini
Nel caso qualcuno stia ancora cercando una soluzione senza dipendenza e se hai un file .
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);
Se non vuoi usare la libreria commons-io di Apache, questo frammento è preso dalla classe sun.misc.IOUtils. È quasi due volte più veloce dell'implementazione comune utilizzando 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: puoi evitare del tutto il buffer.
Codice copiato da http://www.exampledepot.com/egs/java.io/File2ByteArray.html (Sì, è molto dettagliato, ma richiede l'altra metà della memoria come l'altra soluzione.)
// 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()
se offset < bytes.length
o InputStream
non verrà chiuso se viene generata quell'eccezione.
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
in a BufferedInputStream
prima che il codice ridurrebbe le chiamate del sistema operativo e mitigherebbe in modo significativo gli svantaggi delle prestazioni, quel codice eseguirà comunque operazioni di copia manuale non necessarie da un buffer a un altro.
Java 9 ti darà finalmente un bel metodo:
InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();
InputStram.readAllBytes()
quello è one-liner?
So che è troppo tardi ma qui penso che sia una soluzione più pulita più leggibile ...
/**
* 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 (grazie a BufferedReader e 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>);
}
}
Nota che questa soluzione asciuga ritorno a capo ( '\ r') e può essere inappropriato.
String
. OP sta chiedendo byte[]
.
\r
che potrebbe essere un problema. Questo metodo converte i byte in caratteri e viceversa (utilizzando il set di caratteri predefinito per InputStreamReader). Tutti i byte non validi nella codifica dei caratteri predefinita (ad esempio -1 per UTF-8 su Linux) verranno danneggiati, cambiando potenzialmente anche il numero di byte.
Ho provato a modificare la risposta di @ numan con una correzione per la scrittura di dati inutili ma la modifica è stata respinta. Mentre questo breve pezzo di codice non è niente di eccezionale, non vedo altre risposte migliori. Ecco cosa ha più senso per me:
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 non deve essere chiuso. prova / finalmente costruisce omesso per leggibilità
Vedi la InputStream.available()
documentazione:
È particolarmente importante rendersi conto che non è necessario utilizzare questo metodo per ridimensionare un contenitore e supporre che sia possibile leggere l'intero flusso senza dover ridimensionare il contenitore. Tali chiamanti dovrebbero probabilmente scrivere tutto ciò che leggono in un ByteArrayOutputStream e convertirlo in un array di byte. In alternativa, se stai leggendo da un file, File.length restituisce la lunghezza corrente del file (anche se supponendo che la lunghezza del file non possa essere modificata potrebbe essere errata, la lettura di un file è intrinsecamente rigida).
Avvolgilo in un DataInputStream se questo è fuori dal tavolo per qualche motivo, basta usare read per martellare su di esso fino a quando non ti dà un -1 o l'intero blocco richiesto.
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;
}
Stiamo riscontrando un certo ritardo per alcune transazioni AWS, durante la conversione dell'oggetto S3 in ByteArray.
Nota: l'oggetto S3 è un documento PDF (la dimensione massima è 3 mb).
Stiamo usando l'opzione # 1 (org.apache.commons.io.IOUtils) per convertire l'oggetto S3 in ByteArray. Abbiamo notato che S3 fornisce il metodo IOUtils inbuild per convertire l'oggetto S3 in ByteArray, ti chiediamo di confermare qual è il modo migliore per convertire l'oggetto S3 in ByteArray per evitare il ritardo.
Opzione 1:
import org.apache.commons.io.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);
Opzione 2:
import com.amazonaws.util.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);
Fammi sapere se esiste un altro modo migliore per convertire l'oggetto s3 in bytearray
L'altro caso per ottenere l'array di byte corretto tramite stream, dopo aver inviato la richiesta al server e in attesa della risposta.
/**
* 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);
Stai facendo una copia extra se usi ByteArrayOutputStream. Se conosci la lunghezza dello stream prima di iniziare a leggerlo (ad esempio, InputStream è in realtà un FileInputStream e puoi chiamare file.length () sul file o InputStream è una voce del file zip InputStream e puoi chiamare zipEntry. lunghezza ()), quindi è molto meglio scrivere direttamente nell'array byte []: utilizza metà della memoria e consente di risparmiare tempo.
// 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 l'ultima riga sopra tratta dei file che vengono troncati durante la lettura dello stream, se è necessario gestire tale possibilità, ma se il file si allunga durante la lettura dello stream, il contenuto dell'array byte [] non verrà allungato per includere il nuovo contenuto del file, l'array verrà semplicemente troncato alla vecchia lunghezza inputStreamLength .
Io lo uso
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();
}
}
Questa è la mia versione copia-incolla:
@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 e versioni successive:
import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);
sun.misc.IOUtils
non è "Java 7". È una classe proprietaria specifica per l'implementazione che potrebbe non essere presente in altre implementazioni JRE e che può scomparire senza alcun preavviso in una delle prossime versioni.
Ecco una versione ottimizzata, che cerca di evitare il più possibile la copia dei byte di dati:
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;
}
}
Soluzione in Kotlin (funzionerà anche in Java, ovviamente), che include entrambi i casi in cui si conosce la dimensione o meno:
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
}
}
Se conosci le dimensioni, ti consente di risparmiare il doppio della memoria utilizzata rispetto alle altre soluzioni (in un breve momento, ma potrebbe comunque essere utile). Questo perché devi leggere l'intero flusso fino alla fine, quindi convertirlo in un array di byte (simile a ArrayList che converti in un solo array).
Quindi, se sei su Android, ad esempio, e hai qualche Uri da gestire, puoi provare a ottenere le dimensioni usando questo:
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();
}