Odpowiedzi:
Możesz używać Apache Commons IO do obsługi tego i podobnych zadań.
IOUtilsTyp ma statyczną metodę przeczytać InputStreami zwrócić byte[].
InputStream is;
byte[] bytes = IOUtils.toByteArray(is);
Wewnętrznie tworzy to ByteArrayOutputStreami kopiuje bajty na wyjście, a następnie wywołuje toByteArray(). Obsługuje duże pliki, kopiując bajty w blokach 4KiB.
FastArrayListwspólne Apache lub ich miękkie i słabe mapy referencyjne, i wróć, aby powiedzieć mi, jak „dobrze przetestowana” ta biblioteka. To kupa śmieci
InputStream is; byte[] filedata=ByteStreams.toByteArray(is);
Musisz odczytać każdy bajt ze swojego InputStreami zapisać go w ByteArrayOutputStream.
Następnie można pobrać podstawową tablicę bajtów, wywołując 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();
Wreszcie, po dwudziestu latach, dzięki Java 9 istnieje proste rozwiązanie bez potrzeby tworzenia biblioteki innej firmy :
InputStream is;
…
byte[] array = is.readAllBytes();
Zwróć również uwagę na metody wygody readNBytes(byte[] b, int off, int len)i transferTo(OutputStream)zaspokajanie powtarzających się potrzeb.
Użyj waniliowej Java DataInputStreami jej readFullymetody (istnieje od co najmniej Java 1.4):
...
byte[] bytes = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(bytes);
...
Istnieje kilka innych smaków tej metody, ale używam tego cały czas w tym przypadku użycia.
DataInputStreamjest używana głównie do odczytywania typów podstawowych (długich, krótkich, znaków ...) ze strumienia, dzięki czemu możemy postrzegać to użycie jako niewłaściwe użycie klasy.
InputStream.read.
Jeśli zdarzy ci się używać google guava , będzie to tak proste, jak:
byte[] bytes = ByteStreams.toByteArray(inputStream);
ByteStreamsjest opatrzony adnotacją@Beta
Jak zawsze również Spring Framework (Spring-Core od 3.2.2) ma coś dla Ciebie: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();
}
Bezpieczne rozwiązanie (z możliwościącloseprawidłowego przesyłania strumieni):
Wersja Java 9+:
final byte[] bytes;
try (inputStream) {
bytes = inputStream.readAllBytes();
}Wersja 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);
}
}
}Wersja Kotlin (gdy Java 9+ nie jest dostępna):
@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()
}
}
Aby uniknąć zagnieżdżenia, usezobacz tutaj .
Czy naprawdę potrzebujesz tego obrazu jako byte[]? Czego dokładnie oczekujesz wbyte[] - pełnej zawartości pliku obrazu, zakodowanego w jakimkolwiek formacie, w którym znajduje się plik obrazu, lub wartości pikseli RGB?
Inne odpowiedzi tutaj pokazują, jak wczytać plik do pliku byte[]. Twój byte[]będzie zawierać dokładną zawartość pliku, i trzeba by dekodowania że nic zrobić z danymi obrazu.
Standardowym API Java do odczytu (i zapisu) obrazów jest ImageIO API, które można znaleźć w pakiecie javax.imageio. Możesz odczytać obraz z pliku za pomocą tylko jednego wiersza kodu:
BufferedImage image = ImageIO.read(new File("image.jpg"));
To da ci, a BufferedImagenie byte[]. Aby uzyskać dane obrazu, możesz zadzwonić getRaster()na BufferedImage. To da ci Rasterobiekt, który ma metody dostępu do danych pikseli (ma kilka metod getPixel()/ getPixels()).
Odnośnika do dokumentacji API javax.imageio.ImageIO, java.awt.image.BufferedImage, java.awt.image.Rasteritd.
ImageIO domyślnie obsługuje wiele formatów obrazu: JPEG, PNG, BMP, WBMP i GIF. Możliwe jest dodanie obsługi większej liczby formatów (potrzebujesz wtyczki, która implementuje interfejs dostawcy usług ImageIO).
Zobacz także następujący samouczek: Praca z obrazami
W przypadku, gdy ktoś nadal szuka rozwiązania bez zależności i jeśli masz plik .
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);
Jeśli nie chcesz korzystać z biblioteki Apache commons-io, ten fragment kodu jest pobierany z klasy sun.misc.IOUtils. Jest prawie dwa razy szybszy niż zwykła implementacja przy użyciu 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: Możesz całkowicie uniknąć buforowania.
Kod skopiowany z http://www.exampledepot.com/egs/java.io/File2ByteArray.html (Tak, jest bardzo szczegółowy, ale potrzebuje innego rozmiaru pamięci niż inne rozwiązanie).
// 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()czy offset < bytes.lengthlub InputStreamnie zostanie zamknięty, jeśli ten wyjątek zostanie zgłoszony.
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();
InputStreamw sposób BufferedInputStreamprzed tym kodem zmniejszyłoby OS połączeń i złagodzenie niedogodności wydajność znacznie, że kod będzie nadal robić niepotrzebnej pracy ręcznej kopiowania z jednego bufora do innego.
Java 9 da ci wreszcie fajną metodę:
InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();
InputStram.readAllBytes()że jest to jedna linijka?
Wiem, że jest za późno, ale myślę, że jest to czystsze rozwiązanie, które jest bardziej czytelne ...
/**
* 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 sposób (dzięki BufferedReader i Adamowi Bienowi )
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>);
}
}
Zauważ, że to rozwiązanie powoduje wyczyszczenie znaku powrotu karetki („\ r”) i może być nieodpowiednie.
String. OP prosi o byte[].
\rmoże być problem. Ta metoda konwertuje bajty na znaki iz powrotem (przy użyciu domyślnego zestawu znaków dla InputStreamReader). Wszelkie bajty, które nie są prawidłowe w domyślnym kodowaniu znaków (powiedzmy -1 dla UTF-8 w systemie Linux), zostaną uszkodzone, potencjalnie nawet zmieniając liczbę bajtów.
Próbowałem edytować odpowiedź @ numan z poprawką do zapisywania danych śmieci, ale edycja została odrzucona. Chociaż ten krótki fragment kodu nie jest niczym genialnym, nie widzę innej lepszej odpowiedzi. Oto, co ma dla mnie największy sens:
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 nie musi być zamknięty. konstrukcje try / wreszcie zostały pominięte ze względu na czytelność
Zobacz InputStream.available()dokumentację:
Szczególnie ważne jest, aby zdawać sobie sprawę, że nie wolno używać tej metody do określania rozmiaru kontenera i zakładać, że można odczytać cały strumień bez konieczności zmiany rozmiaru kontenera. Tacy wywołujący powinni prawdopodobnie zapisać wszystko, co czytają, w ByteArrayOutputStream i przekonwertować to na tablicę bajtów. Alternatywnie, jeśli czytasz z pliku, File.length zwraca bieżącą długość pliku (choć zakładanie, że długość pliku nie może się zmienić, może być niepoprawna, czytanie pliku jest z natury ryzykowne).
Zawiń go w DataInputStream, jeśli z jakiegoś powodu jest on poza tabelą, po prostu użyj read, aby młotkować, aż da ci -1 lub cały żądany blok.
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;
}
Widzimy pewne opóźnienie dla kilku transakcji AWS, podczas konwertowania obiektu S3 na ByteArray.
Uwaga: Obiekt S3 jest dokumentem PDF (maksymalny rozmiar to 3 mb).
Używamy opcji nr 1 (org.apache.commons.io.IOUtils) do konwersji obiektu S3 na ByteArray. Zauważyliśmy, że S3 udostępnia wbudowaną metodę IOUtils do konwersji obiektu S3 na ByteArray, prosimy o potwierdzenie najlepszego sposobu konwersji obiektu S3 na ByteArray, aby uniknąć opóźnienia.
Opcja 1:
import org.apache.commons.io.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);
Opcja 2:
import com.amazonaws.util.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);
Daj mi również znać, jeśli mamy inny lepszy sposób na konwersję obiektu s3 na bytearray
Drugi przypadek uzyskania poprawnej tablicy bajtów przez strumień, po wysłaniu żądania do serwera i oczekiwaniu na odpowiedź.
/**
* 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);
Robisz dodatkową kopię, jeśli używasz ByteArrayOutputStream. Jeśli znasz długość strumienia, zanim zaczniesz go czytać (np. InputStream to tak naprawdę FileInputStream i możesz wywołać file.length () w pliku, lub InputStream to pozycja zipfile InputStream i możesz wywołać zipEntry. length ()), wtedy znacznie lepiej jest pisać bezpośrednio do tablicy byte [] - zużywa połowę pamięci i oszczędza czas.
// 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);
Uwaga: ostatni wiersz powyżej dotyczy obcinania plików podczas odczytywania strumienia, jeśli trzeba skorzystać z tej możliwości, ale jeśli plik wydłuża się podczas odczytywania strumienia, zawartość tablicy byte [] nie zostanie przedłużona aby uwzględnić nową zawartość pliku, tablica zostanie po prostu obcięta do starej długości inputStreamLength .
Używam tego.
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();
}
}
To jest moja wersja kopiuj-wklej:
@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 i nowsze wersje:
import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);
sun.misc.IOUtilsto nie „Java 7”. Jest to zastrzeżona, specyficzna dla implementacji klasa, która może nie być obecna w innych implementacjach JRE i może zniknąć bez ostrzeżenia w jednej z kolejnych wydań.
Oto zoptymalizowana wersja, która stara się unikać kopiowania bajtów danych w jak największym stopniu:
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;
}
}
Rozwiązanie w Kotlinie (oczywiście będzie działało również w Javie), które obejmuje oba przypadki, gdy znasz rozmiar lub nie:
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
}
}
Jeśli znasz rozmiar, oszczędza to podwójnego wykorzystania pamięci w porównaniu do innych rozwiązań (w krótkiej chwili, ale nadal może być przydatne). Jest tak, ponieważ musisz przeczytać cały strumień do końca, a następnie przekonwertować go na tablicę bajtów (podobną do ArrayList, którą konwertujesz na samą tablicę).
Na przykład, jeśli korzystasz z Androida i masz trochę Uri do obsługi, możesz spróbować uzyskać rozmiar za pomocą tego:
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();
}