Réponses:
Vous pouvez utiliser Apache Commons IO pour gérer cela et des tâches similaires.
Le IOUtils
type a une méthode statique pour lire InputStream
et renvoyer un byte[]
.
InputStream is;
byte[] bytes = IOUtils.toByteArray(is);
En interne, cela crée un ByteArrayOutputStream
et copie les octets dans la sortie, puis appelle toByteArray()
. Il gère les fichiers volumineux en copiant les octets dans des blocs de 4 Ko.
FastArrayList
ou leurs cartes de référence douces et faibles et revenir me dire à quel point cette bibliothèque est "bien testée". C'est un tas d'ordures
InputStream is;
byte[] filedata=ByteStreams.toByteArray(is);
Vous devez lire chaque octet de votre InputStream
et l'écrire dans a ByteArrayOutputStream
.
Vous pouvez ensuite récupérer le tableau d'octets sous-jacent en appelant 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();
Enfin, après vingt ans, il existe une solution simple sans avoir besoin d'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 la transferTo(OutputStream)
réponse aux besoins récurrents.
Utilisez le Java vanilla DataInputStream
et sa readFully
méthode (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.
DataInputStream
est principalement utilisée pour lire les types primaires (Longs, Shorts, Chars ...) à partir d'un flux, nous pouvons donc voir cette utilisation comme une mauvaise utilisation de la classe.
InputStream.read
.
Si vous utilisez google goyave , ce sera aussi simple que:
byte[] bytes = ByteStreams.toByteArray(inputStream);
ByteStreams
est annoté avec@Beta
Comme toujours, le framework Spring (Spring-core depuis 3.2.2) a quelque chose pour vous: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();
}
Solution sûre (avec capacité declose
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);
}
}
}
Version Kotlin (lorsque Java 9+ n'est pas accessible):
@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 l'imbrication, use
voir ici .
Avez-vous vraiment besoin de l'image en tant que byte[]
? Qu'attendez-vous exactement dans le byte[]
- le contenu complet d'un fichier image, encodé dans le format dans lequel le fichier image est, ou les valeurs de pixels RVB?
D'autres réponses ici vous montrent comment lire un fichier dans un fichier byte[]
. Votre byte[]
contiendra le contenu exact du fichier et vous devrez le décoder pour faire 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 pouvez trouver 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 un BufferedImage
, pas un byte[]
. Pour accéder aux données d'image, vous pouvez appeler getRaster()
le BufferedImage
. Cela vous donnera un Raster
objet, qui a des méthodes pour accéder aux données de pixel (il en a plusieurs getPixel()
/ getPixels()
méthodes).
Lookup la documentation de l' API pour 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 la prise en charge de plusieurs formats (vous auriez besoin d'un plug-in qui implémente l'interface du fournisseur de services ImageIO).
Voir également le didacticiel suivant: Utilisation des images
Dans le cas où quelqu'un est toujours à la recherche d'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);
Si vous ne souhaitez pas utiliser la bibliothèque Apache commons-io, cet extrait est extrait de la classe sun.misc.IOUtils. C'est presque deux fois plus rapide 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;
}
@Adamski: Vous pouvez éviter complètement le tampon.
Code copié depuis http://www.exampledepot.com/egs/java.io/File2ByteArray.html (Oui, il est très verbeux, mais nécessite la moitié de la taille de la mémoire comme l'autre solution.)
// 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
ou InputStream
ne sera pas fermé si cette exception est levée.
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
dans un BufferedInputStream
avant ce code réduise les appels du système d'exploitation et atténue considérablement les inconvénients de performances, ce code effectuera toujours un travail de copie manuelle inutile d'un tampon à un autre.
Java 9 vous donnera enfin une belle méthode:
InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();
InputStram.readAllBytes()
qui est à une ligne?
Je sais qu'il est trop tard mais ici je pense que c'est une solution plus propre et 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();
}
Java 8 way (merci à 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ée.
String
. OP demande byte[]
.
\r
que cela pourrait être un problème. Cette méthode convertit les octets en caractères et inversement (en utilisant le jeu de caractères par défaut pour InputStreamReader). Tous les octets qui ne sont pas valides dans le codage de caractères par défaut (disons -1 pour UTF-8 sous Linux) seront corrompus, ce qui pourrait même changer le nombre d'octets.
J'ai essayé de modifier la réponse de @ numan avec un correctif pour écrire des données de poubelle, mais la modification a été rejetée. Bien que ce court morceau de code ne soit rien de brillant, je ne vois pas d'autre meilleure réponse. Voici ce qui me semble le plus logique:
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é. essayez / finalement les constructions omises pour la lisibilité
Consultez la InputStream.available()
documentation:
Il est particulièrement important de réaliser que vous ne devez pas utiliser cette 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 devraient probablement écrire tout ce qu'ils lisent dans un ByteArrayOutputStream et le convertir en un tableau d'octets. Alternativement, si vous lisez 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, la lecture d'un fichier est intrinsèquement racée).
Enveloppez-le dans un DataInputStream si cela est hors de la table pour une raison quelconque, utilisez simplement read pour marteler dessus jusqu'à ce qu'il vous donne un -1 ou le bloc entier que vous avez 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;
}
Nous constatons un certain retard pour quelques transactions AWS, lors de la conversion de l'objet S3 en ByteArray.
Remarque: l'objet S3 est un document PDF (la taille maximale est de 3 Mo).
Nous utilisons l'option # 1 (org.apache.commons.io.IOUtils) pour convertir l'objet S3 en ByteArray. Nous avons remarqué que S3 fournit la méthode IOUtils inbuild pour convertir l'objet S3 en ByteArray, nous vous demandons de confirmer quelle est la meilleure façon de convertir l'objet S3 en ByteArray pour éviter le retard.
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);
Faites-moi également savoir si nous avons une autre meilleure façon de convertir l'objet s3 en bytearray
L'autre cas pour obtenir un 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);
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 alors préférable d'écrire directement dans le tableau d'octets [] - 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);
NB la dernière ligne ci-dessus traite des fichiers qui sont tronqués pendant la lecture du flux, si vous avez besoin de gérer cette possibilité, mais si le fichier s'allonge pendant la lecture du flux, le contenu du tableau d'octets [] ne sera pas allongé pour inclure le nouveau contenu du fichier, le tableau sera simplement tronqué à l'ancienne longueur inputStreamLength .
J'utilise ça.
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();
}
}
Voici 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();
}
Java 7 et versions ultérieures:
import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);
sun.misc.IOUtils
n'est pas «Java 7». Il s'agit d'une classe propriétaire spécifique à l'implémentation qui peut ne pas être présente dans d'autres implémentations JRE et peut disparaître sans avertissement dans l'une des prochaines versions.
Voici une version optimisée, qui essaie d'éviter autant que possible de copier des 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;
}
}
Solution dans Kotlin (fonctionnera également en Java, bien sûr), qui comprend les deux cas où vous connaissez la taille ou non:
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 vous connaissez la taille, cela vous évite d'avoir le double de la mémoire utilisée par rapport aux autres solutions (dans un bref instant, mais pourrait tout de même être utile). C'est parce que vous devez lire l'intégralité du flux à la fin, puis le convertir en un tableau d'octets (similaire à ArrayList que vous convertissez en un simple tableau).
Donc, si vous êtes sur Android, par exemple, et que vous avez un Uri à gérer, vous pouvez essayer d'obtenir la taille en utilisant ceci:
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();
}