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.
Jeśli chcesz napisać 4 wiersze kodu, uważasz, że warto zaimportować zależność innej firmy?
oxbow_lakes
217
Jeśli istnieje biblioteka, która obsługuje ten wymóg i zajmuje się przetwarzaniem dużych plików i jest dobrze przetestowana, z pewnością pytanie brzmi: dlaczego sam bym to napisał? Słoik ma tylko 107 KB, a jeśli potrzebujesz jednej metody, prawdopodobnie również użyjesz innych
Rich Seller
242
@oxbow_lakes: Biorąc pod uwagę oszałamiającą liczbę niewłaściwych implementacji tej funkcji, które widziałem w życiu programisty, czuję, że tak , bardzo warto zewnętrzną zależność, aby zrobić to dobrze.
Joachim Sauer
17
Dlaczego nie pójść i rzucić okiem na takie 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
oxbow_lakes
87
Oprócz Apache commons-io, sprawdź klasę ByteStreams od Google Guava . InputStream is;byte[] filedata=ByteStreams.toByteArray(is);
michaelok
446
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 =newByteArrayOutputStream();int nRead;byte[] data =newbyte[16384];while((nRead = is.read(data,0, data.length))!=-1){
buffer.write(data,0, nRead);}return buffer.toByteArray();
Co z rozmiarem nowo utworzonego bajtu []. Dlaczego to 16384? Jak mogę określić dokładnie odpowiedni rozmiar? Dziękuję Ci bardzo.
Ondrej Bozek
6
16384 jest dość arbitralnym wyborem, chociaż mam tendencję do faworyzowania potęg 2, aby zwiększyć szansę wyrównania tablicy z granicami słów. Odpowiedź pihentagy pokazuje, jak można uniknąć używania bufora pośredniego, ale raczej przydzielić tablicę o odpowiednim rozmiarze. O ile nie masz do czynienia z dużymi plikami, osobiście wolę powyższy kod, który jest bardziej elegancki i może być używany do InputStreams, w których liczba bajtów do odczytania nie jest wcześniej znana.
Adamski,
@Adamski Czy tworzenie tablicy bajtów nie jest o wiele większe niż można oczekiwać w danych w strumieniu, marnować pamięć?
Paul Brewczynski
@bluesm: Tak, to prawda. Jednak w moim przykładzie tablica bajtów ma tylko 16 KB i jest tak mała jak na dzisiejsze standardy. Oczywiście pamięć ta zostanie później ponownie zwolniona.
Adamski
5
@Adamski Wiele urządzeń infrastruktury, serwerów sieciowych i komponentów warstwy systemu operacyjnego używa buforów 4K do przenoszenia danych, więc to jest powód dokładnej liczby, ale najważniejsze jest to, że uzyskuje się tak niewielki wzrost wydajności, przekraczając 4K że jest ogólnie uważane za marnotrawstwo pamięci. Zakładam, że to nadal prawda, ponieważ miałem dziesięcioletnią wiedzę, którą miałem!
312
Wreszcie, po dwudziestu latach, dzięki Java 9 istnieje proste rozwiązanie bez potrzeby tworzenia biblioteki innej firmy :
+1 za korzystanie ze standardowych bibliotek zamiast zależności innej firmy. Niestety nie działa dla mnie, ponieważ nie znam początkowej długości strumienia.
Andrew Spencer
2
co to jest imgFile? To nie może być InputStream, który miał być wkładem tej metody
Janus Troelsen
4
@janus jest to „plik”. w ten sposób działa tylko wtedy, gdy znasz długość pliku lub liczbę bajtów do odczytania.
dermoritz
5
Interesująca rzecz, ale musisz znać dokładną długość (części) strumienia do odczytania. Co więcej, klasa 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.
Olivier Faucheux
17
Jeśli znasz już długość danych do odczytu ze strumienia, nie jest to lepsze niż InputStream.read.
Logan Pickup
119
Jeśli zdarzy ci się używać google guava , będzie to tak proste, jak:
Jak większość innych, chciałem uniknąć korzystania z biblioteki innej firmy do czegoś tak prostego, ale Java 9 nie jest w tej chwili opcją ... na szczęście już korzystałem z Springa.
scottysseus
42
publicstaticbyte[] getBytesFromInputStream(InputStream is)throwsIOException{ByteArrayOutputStream os =newByteArrayOutputStream();byte[] buffer =newbyte[0xFFFF];for(int len = is.read(buffer); len !=-1; len = is.read(buffer)){
os.write(buffer,0, len);}return os.toByteArray();}
Jest to przykład i zwięzłość jest na porządku dziennym. Zwrócenie tutaj wartości null byłoby właściwym wyborem w niektórych przypadkach (chociaż w środowisku produkcyjnym miałbyś również odpowiednią obsługę wyjątków i dokumentację).
11
Rozumiem zwięzłość w przykładzie, ale dlaczego nie po prostu sprawić, aby przykładowa metoda generowała wyjątek IOException zamiast połykać go i zwracać bezwartościową wartość?
pendor
4
skorzystałem z możliwości zmiany z „return null” na „throw IOException”
kritzikratzi
3
Try-with-resources nie jest tutaj potrzebne, ponieważ ByteArrayOutputStream # close () nic nie robi. (ByteArrayOutputStream # flush () nie jest potrzebny i też nie robi nic.)
Luke Hutchison
25
Bezpieczne rozwiązanie (z możliwościącloseprawidłowego przesyłania strumieni):
@Throws(IOException::class)
fun InputStream.readAllBytes():ByteArray{
val bufLen =4*0x400// 4KB
val buf =ByteArray(bufLen)
var readLen:Int=0ByteArrayOutputStream().use { o ->this.use { i ->while(i.read(buf,0, bufLen).also { readLen = it }!=-1)
o.write(buf,0, readLen)}return o.toByteArray()}}
Czy to nie znaczy, że w pewnym momencie użyłbyś podwójnej pamięci, ponieważ masz zarówno bufor, jak i tablicę bajtów? Czy nie ma sposobu, aby wysłać bajty bezpośrednio do wyjściowej tablicy bajtów?
programista Androida
@androiddeveloper; Przepraszam. Nie znam odpowiedzi! Ale nie sądzę. Myślę, że ten sposób (użycie bufora) jest sposobem zoptymalizowanym.
Mir-Ismaili
Sprawdziłem i tak, ale wydaje się, że jest to jedyne rozwiązanie, które możesz wybrać, gdy nie znasz rozmiaru. Jeśli znasz już rozmiar, możesz bezpośrednio utworzyć tablicę bajtów o podanym rozmiarze i wypełnić go. Tak więc używasz funkcji, która otrzyma parametr wielkości bajtu, a jeśli jest poprawna, użyj go do bezpośredniego utworzenia i wypełnienia tablicy bajtów, bez tworzenia żadnego innego dużego obiektu.
programista Androida
@androiddeveloper; Dziękuję za informację. Nie znałem ich.
Mir-Ismaili
19
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:
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).
Powiedzmy, co jeśli tablica bajtów jest zbyt duża, co może spowodować OOM dla sterty? Czy istnieje podobne rozwiązanie, które będzie wykorzystywać JNI do przechowywania bajtów, a później będziemy mogli użyć inputStream z przechowywanych tam danych (rodzaj tymczasowej pamięci podręcznej)?
programista Androida
14
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:
Jest to trochę dziwne rozwiązanie, długość jest górną granicą długości tablicy. Jeśli znasz długość, wystarczy: byte [] output = new byte [length]; is.read (wyjście); (ale zobacz moją odpowiedź)
Luke Hutchison
@ luke-hutchison, jak powiedziałem, to rozwiązanie sun.misc.IOUtils. W najczęstszych przypadkach nie znasz z góry rozmiaru InputStream, więc jeśli (length == -1) length = Integer.MAX_VALUE; dotyczy. To rozwiązanie działa, nawet jeśli podana długość jest większa niż długość InputStream.
Kristian Kraljic
@LukeHutchison Jeśli znasz długość, możesz poradzić sobie z kilkoma liniami. Jeśli spojrzysz na każdą odpowiedź, wszyscy narzekają, że długość nie jest znana. Na koniec odpowiedź, która jest standardowa, może być używana z Java 7 Android i nie wymaga żadnej zewnętrznej biblioteki.
Csaba Toth
11
ByteArrayOutputStream out =newByteArrayOutputStream();byte[] buffer =newbyte[1024];while(true){int r = in.read(buffer);if(r ==-1)break;
out.write(buffer,0, r);}byte[] ret = out.toByteArray();
// Returns the contents of the file in a byte array.publicstaticbyte[] getBytesFromFile(File file)throwsIOException{InputStream is =newFileInputStream(file);// Get the size of the filelong 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 databyte[] bytes =newbyte[(int)length];// Read in the bytesint 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 inif(offset < bytes.length){thrownewIOException("Could not completely read file "+file.getName());}// Close the input stream and return bytes
is.close();return bytes;}
Oczywiście, ale powinni znać rozmiar: „Chcę przeczytać obraz”
pihentagy,
1
jeśli znasz rozmiar, java dostarcza kod dla ciebie. zobacz moją odpowiedź lub google dla „DataInputStream” i jest to metoda readFully.
dermoritz
Powinieneś dodać, is.close()czy offset < bytes.lengthlub InputStreamnie zostanie zamknięty, jeśli ten wyjątek zostanie zgłoszony.
Jared Rummler
3
Zatem lepiej, powinieneś użyć try-with-resources
pihentagy
8
InputStream is ...ByteArrayOutputStream bos =newByteArrayOutputStream();int next = in.read();while(next >-1){
bos.write(next);
next = in.read();}
bos.flush();byte[] result = bos.toByteArray();
bos.close();
Jednak zwykle system operacyjny już buforuje wystarczająco dużo, aby nie było to wielkim zmartwieniem dla mniejszych plików. To nie tak, że głowica dysku twardego odczytuje każdy bajt osobno (dysk twardy to obracająca się szklana płytka z kodowanymi magnetycznie informacjami, trochę jak ta dziwna ikona, której używamy do zapisywania danych: P).
Maarten Bodewes
6
@Maarten Bodewes: większość urządzeń ma pewien rodzaj transferu bloków, więc nie każdy odczyt () spowoduje rzeczywiście dostęp do urządzenia, ale posiadanie wywołania OS na bajt jest już wystarczające, aby zabić wydajność. Podczas owijania 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.
Jaka jest różnica między tym a tym, InputStram.readAllBytes()że jest to jedna linijka?
Slava Semushin
2
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.
*/publicstaticbyte[] streamToByteArray(InputStream stream)throwsIOException{byte[] buffer =newbyte[1024];ByteArrayOutputStream os =newByteArrayOutputStream();int line =0;// read bytes from stream, and store them in bufferwhile((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();}
To nie tylko \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.
seanf
Wydaje się, że to dobra odpowiedź, ale zorientowana na tekst. Kupujący strzeż się.
Wheezil
1
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 =newByteArrayOutputStream();byte[] buffer =newbyte[1024];// you can configure the buffer sizeint length;while((length = in.read(buffer))!=-1) out.write(buffer,0, length);//copy streams
in.close();// call this in a finally blockbyte[] result = out.toByteArray();
btw ByteArrayOutputStream nie musi być zamknięty. konstrukcje try / wreszcie zostały pominięte ze względu na czytelność
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).
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 =newSocket(IP, port);// mSocket.setSoTimeout(30000);DataOutputStream mDos =newDataOutputStream(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 =newDataInputStream(mSocket.getInputStream());byte[] data =newbyte[mDis.available()];// Collecting data into byte arrayfor(int i =0; i < data.length; i++)
data[i]= mDis.readByte();// Converting collected data in byte array into String.String RESPONSE =newString(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[] arraybyte[] buf =newbyte[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 operationbyte[] 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 .
Dodaj wyjaśnienie wraz z odpowiedzią, w jaki sposób ta odpowiedź pomaga OP w rozwiązaniu bieżącego problemu
ρяσсρѕя K
0
To jest moja wersja kopiuj-wklej:
@SuppressWarnings("empty-statement")publicstaticbyte[] inputStreamToByte(InputStream is)throwsIOException{if(is ==null){returnnull;}// Define a size if you have an idea of it.ByteArrayOutputStream r =newByteArrayOutputStream(2048);byte[] read =newbyte[512];// Your buffer size.for(int i;-1!=(i = is.read(read)); r.write(read,0, i));
is.close();return r.toByteArray();}
Ten fragment kodu może rozwiązać pytanie, ale wyjaśnienie naprawdę pomaga poprawić jakość posta. Pamiętaj, że w przyszłości odpowiadasz na pytanie czytelników, a ci ludzie mogą nie znać przyczyn Twojej sugestii kodu.
Ferrybig
0
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ń.
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 ->nullelse->{
val sizeInt = size.toInt()
val result =ByteArray(sizeInt)
readBytesIntoByteArray(result, sizeInt)
result
}}}
fun InputStream.readBytesIntoByteArray(byteArray:ByteArray,bytesToRead:Int=byteArray.size){
var offset =0while(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/878126FileUtilEx.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 =0Lwhile(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 =newByteArrayOutputStream();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();}
Zamykanie i opróżnianie bos to marnowanie kliknięć na klawiaturze. Zamknięcie strumienia wejściowego może pomóc. Czytanie jednego bajtu na raz jest nieefektywne. Zobacz odpowiedź numana.
Odpowiedzi:
Możesz używać Apache Commons IO do obsługi tego i podobnych zadań.
IOUtils
Typ ma statyczną metodę przeczytaćInputStream
i zwrócićbyte[]
.Wewnętrznie tworzy to
ByteArrayOutputStream
i kopiuje bajty na wyjście, a następnie wywołujetoByteArray()
. Obsługuje duże pliki, kopiując bajty w blokach 4KiB.źródło
FastArrayList
wspólne Apache lub ich miękkie i słabe mapy referencyjne, i wróć, aby powiedzieć mi, jak „dobrze przetestowana” ta biblioteka. To kupa śmieciInputStream is;
byte[] filedata=ByteStreams.toByteArray(is);
Musisz odczytać każdy bajt ze swojego
InputStream
i zapisać go wByteArrayOutputStream
.Następnie można pobrać podstawową tablicę bajtów, wywołując
toByteArray()
:źródło
Wreszcie, po dwudziestu latach, dzięki Java 9 istnieje proste rozwiązanie bez potrzeby tworzenia biblioteki innej firmy :
Zwróć również uwagę na metody wygody
readNBytes(byte[] b, int off, int len)
itransferTo(OutputStream)
zaspokajanie powtarzających się potrzeb.źródło
Użyj waniliowej Java
DataInputStream
i jejreadFully
metody (istnieje od co najmniej Java 1.4):Istnieje kilka innych smaków tej metody, ale używam tego cały czas w tym przypadku użycia.
źródło
DataInputStream
jest 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:
źródło
ByteStreams
jest opatrzony adnotacją@Beta
Jak zawsze również Spring Framework (Spring-Core od 3.2.2) ma coś dla Ciebie:
StreamUtils.copyToByteArray()
źródło
źródło
Bezpieczne rozwiązanie (z możliwością
close
prawidłowego przesyłania strumieni):Wersja Java 9+:
Wersja Java 8:
Wersja Kotlin (gdy Java 9+ nie jest dostępna):
Aby uniknąć zagnieżdżenia,
use
zobacz tutaj .źródło
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ójbyte[]
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:To da ci, a
BufferedImage
niebyte[]
. Aby uzyskać dane obrazu, możesz zadzwonićgetRaster()
naBufferedImage
. To da ciRaster
obiekt, który ma metody dostępu do danych pikseli (ma kilka metodgetPixel()
/getPixels()
).Odnośnika do dokumentacji API
javax.imageio.ImageIO
,java.awt.image.BufferedImage
,java.awt.image.Raster
itd.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
źródło
W przypadku, gdy ktoś nadal szuka rozwiązania bez zależności i jeśli masz plik .
źródło
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:
źródło
źródło
@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).
źródło
is.close()
czyoffset < bytes.length
lubInputStream
nie zostanie zamknięty, jeśli ten wyjątek zostanie zgłoszony.źródło
InputStream
w sposóbBufferedInputStream
przed 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ę:
źródło
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 ...
źródło
Java 8 sposób (dzięki BufferedReader i Adamowi Bienowi )
Zauważ, że to rozwiązanie powoduje wyczyszczenie znaku powrotu karetki („\ r”) i może być nieodpowiednie.
źródło
String
. OP prosi obyte[]
.\r
moż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:
btw ByteArrayOutputStream nie musi być zamknięty. konstrukcje try / wreszcie zostały pominięte ze względu na czytelność
źródło
Zobacz
InputStream.available()
dokumentację:źródło
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.
źródło
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:
Opcja 2:
Daj mi również znać, jeśli mamy inny lepszy sposób na konwersję obiektu s3 na bytearray
źródło
Drugi przypadek uzyskania poprawnej tablicy bajtów przez strumień, po wysłaniu żądania do serwera i oczekiwaniu na odpowiedź.
źródło
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.
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 .
źródło
Używam tego.
źródło
To jest moja wersja kopiuj-wklej:
źródło
Java 7 i nowsze wersje:
źródło
sun.misc.IOUtils
to 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ń.Możesz wypróbować Cactoos :
źródło
Oto zoptymalizowana wersja, która stara się unikać kopiowania bajtów danych w jak największym stopniu:
źródło
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:
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:
źródło
źródło