La conversione InputStream per byte array in Java
-
13-09-2019 - |
Domanda
Come faccio a leggere un intero InputStream
in una matrice di byte?
Soluzione
È possibile utilizzare Apache Commons IO per gestire questa e simili attività.
Il tipo IOUtils
ha un metodo statico per leggere un InputStream
e restituire una byte[]
.
InputStream is;
byte[] bytes = IOUtils.toByteArray(is);
Internamente questo crea un ByteArrayOutputStream
e copia i byte per l'uscita, poi chiama toByteArray()
. Gestisce file di grandi dimensioni copiando i byte in blocchi di 4KiB.
Altri suggerimenti
Hai bisogno di leggere ogni byte dal InputStream
e scrivere ad un ByteArrayOutputStream
. È quindi possibile recuperare la matrice di byte sottostante chiamando toByteArray()
; per es.
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();
Infine, dopo venti anni, c'è 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 transferTo(OutputStream)
soddisfare le esigenze dei ricorrenti
DataInputStream
Usa vaniglia Java e il suo metodo readFully
(esiste almeno dal Java 1.4):
...
byte[] bytes = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(bytes);
...
Ci sono alcuni altri sapori di questo metodo, ma io uso questo tutto il tempo per questo caso d'uso.
Se vi capita di usare google guava , sarà semplice come:
byte[] bytes = ByteStreams.toByteArray(inputStream);
Come sempre, anche framework Spring (primavera-core dal 3.2.2) ha qualcosa per voi: 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();
}
Avete veramente bisogno l'immagine come byte[]
? Che cosa esattamente cosa si aspetta nel byte[]
-? L'intero contenuto di un file di immagine, codificato in qualsiasi formato file di immagine è in, o valori dei pixel RGB
Altre risposte qui si mostrano come leggere un file in un byte[]
. Il tuo byte[]
conterrà il contenuto esatto del file, e avresti bisogno di decodificare che a fare qualsiasi cosa con i dati dell'immagine.
API standard di Java per la lettura (e scrittura) immagini è l'API ImageIO, che potete trovare nella javax.imageio
pacchetto. Si può leggere in un'immagine da un file con una sola riga di codice:
BufferedImage image = ImageIO.read(new File("image.jpg"));
Questo vi darà un BufferedImage
, non un byte[]
. Per ottenere i dati di immagine, è possibile chiamare getRaster()
sul BufferedImage
. Questo vi darà un oggetto Raster
, che dispone di metodi per accedere ai dati dei pixel (che ha diversi metodi getPixel()
/ getPixels()
).
Lookup la documentazione delle 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. E 'possibile aggiungere il supporto per più formati (avresti bisogno di un plug-in che implementa l'interfaccia provider di servizi ImageIO).
Si veda anche il seguente tutorial: Lavorare con le immagini
Se non si desidera utilizzare la libreria Apache commons-io, questo frammento è tratto dalla classe sun.misc.IOUtils. E 'quasi due volte più veloce l'attuazione 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;
}
Nel caso qualcuno è ancora alla ricerca di una soluzione, senza una dipendenza e Se si dispone di 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);
sicurezza Soluzione (con capacità di close
flussi correttamente):
-
Java 9+ versione:
final byte[] bytes; try (inputStream) { bytes = inputStream.readAllBytes(); }
-
Java 8 versione:
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 versione (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
use
nidificato vedere qui .
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();
@Adamski:. È possibile evitare del tutto di buffer
Codice copiato da http://www.exampledepot.com/egs/java.io/File2ByteArray. html (Sì, è molto verboso, ma ha bisogno la metà delle dimensioni 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;
}
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();
Java 9 vi darà finalmente un metodo piacevole:
InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();
Lo so che è troppo tardi, ma qui penso che è la soluzione più pulita che è 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 (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 salviette di ritorno a capo (' ') e può essere inappropriato.
Ho provato a modificare @ risposta di Numan con una correzione per la scrittura di caratteri privi di significato, ma modifica è stata respinta. Mentre questo breve pezzo di codice è niente di eccezionale non riesco a vedere qualsiasi altra risposta migliore. Ecco ciò che rende 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. try / finally costrutti omesso per migliorare la leggibilità
Vedere la documentazione InputStream.available()
:
E 'particolarmente importante rendersi conto che non è necessario utilizzare questo metodo per dimensioni di un contenitore e supponiamo che si può leggere l'interezza del torrente senza la necessità di ridimensionare il contenitore. tali chiamanti dovrebbe probabilmente scrivere tutto quello che leggono ad un ByteArrayOutputStream e convertire 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 può cambiare non può essere corretto, lettura di un file è intrinsecamente filante).
Java 7 e versioni successive:
import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);
L'altro caso per ottenere corretto array di byte via streaming, dopo invia una richiesta al server e di attesa per la 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);
Si sta facendo una copia in più se si utilizza ByteArrayOutputStream. Se si conosce la lunghezza del flusso prima di iniziare a leggerlo (ad esempio, l'InputStream è in realtà un FileInputStream, ed è possibile chiamare file.length () sul file, oppure l'InputStream è una voce file zip InputStream, ed è possibile chiamare ZipEntry. lunghezza ()), quindi è molto meglio scrivere direttamente nel byte [] array -. usa metà della memoria, e 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 offerte con i file sempre troncato mentre il flusso viene letto, se è necessario gestire questa possibilità, ma se il file viene più , mentre il flusso viene letta, il contenuto del byte [ ] array non verrà allungato per includere il nuovo contenuto del file, l'array sarà semplicemente troncato al vecchio lunghezza di inputStreamLength .
Io uso questa.
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 di 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();
}
avvolgerla in un DataInputStream se questo è fuori dal tavolo per qualche ragione, basta usare leggere a martello su di esso fino a quando non ti dà un -1 o l'intero blocco che hai chiesto.
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;
}
È possibile provare Cactoos :
byte[] array = new BytesOf(stream).bytes();
Stiamo assistendo a un certo ritardo per alcune transazioni AWS, durante la conversione oggetto S3 per ByteArray.
. Nota: S3 oggetto è documento PDF (dimensione massima è di 3 MB)
Stiamo usando l'opzione # 1 (org.apache.commons.io.IOUtils) per convertire l'oggetto S3 a ByteArray. Abbiamo notato S3 fornisce il metodo IOUtils inbuild per convertire l'oggetto S3 per ByteArray, stiamo chiediamo di confermare qual è il modo migliore per convertire l'oggetto S3 per 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);
Inoltre vorrei sapere se abbiamo qualche altro modo migliore per convertire l'oggetto s3 a ByteArray
Questa è una versione ottimizzata, che cerca di evitare la copia dei dati byte, per quanto possibile:
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;
}
}
/*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();
}
Questo funziona per me,
if(inputStream != null){
ByteArrayOutputStream contentStream = readSourceContent(inputStream);
String stringContent = contentStream.toString();
byte[] byteArr = encodeString(stringContent);
}
readSourceContent ()
public static ByteArrayOutputStream readSourceContent(InputStream inputStream) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int nextChar;
try {
while ((nextChar = inputStream.read()) != -1) {
outputStream.write(nextChar);
}
outputStream.flush();
} catch (IOException e) {
throw new IOException("Exception occurred while reading content", e);
}
return outputStream;
}
encodeString ()
public static byte[] encodeString(String content) throws UnsupportedEncodingException {
byte[] bytes;
try {
bytes = content.getBytes();
} catch (UnsupportedEncodingException e) {
String msg = ENCODING + " is unsupported encoding type";
log.error(msg,e);
throw new UnsupportedEncodingException(msg, e);
}
return bytes;
}