InputStream
Bir bayt dizisinin tamamını nasıl okuyabilirim ?
InputStream
Bir bayt dizisinin tamamını nasıl okuyabilirim ?
Yanıtlar:
Bu ve benzeri görevleri yerine getirmek için Apache Commons IO'yu kullanabilirsiniz .
IOUtils
Tip bir okumak için statik yöntem vardır InputStream
ve bir dönüş byte[]
.
InputStream is;
byte[] bytes = IOUtils.toByteArray(is);
Dahili olarak bu bir a oluşturur ByteArrayOutputStream
ve baytları çıktıya kopyalar, sonra çağırır toByteArray()
. 4KiB bloklarındaki baytları kopyalayarak büyük dosyaları işler.
FastArrayList
müşterileri gibi şeyler ve onların yumuşak ve zayıf referans Haritalar bir göz atın ve bana bu kütüphane ne kadar "iyi test edilmiş" söylemek için geri gelmek. Çöp yığını
InputStream is;
byte[] filedata=ByteStreams.toByteArray(is);
Her bir baytı kendinizden okumalı InputStream
ve a yazmalısınız ByteArrayOutputStream
.
Ardından, alttaki bayt dizisini arayarak alabilirsiniz 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();
Son olarak, yirmi yıl sonra, Java 9 sayesinde 3. taraf kütüphaneye ihtiyaç duymadan basit bir çözüm var :
InputStream is;
…
byte[] array = is.readAllBytes();
Ayrıca uygunluk yöntemlerini readNBytes(byte[] b, int off, int len)
ve transferTo(OutputStream)
yinelenen ihtiyaçları ele almayı unutmayın .
Vanilya Java'sını DataInputStream
ve readFully
Yöntemini kullanın (en azından Java 1.4'ten beri var):
...
byte[] bytes = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(bytes);
...
Bu yöntemin başka lezzetleri de var, ama bunu her zaman bu kullanım durumu için kullanıyorum.
DataInputStream
birincil olarak bir akıştan birincil türleri (Uzunlar, Kısalar, Karakterler ...) okumak için kullanılır, bu nedenle bu kullanımı sınıfın yanlış kullanımı olarak görebiliriz.
InputStream.read
.
Google guava'yı kullanırsanız , bu kadar basit olacaktır:
byte[] bytes = ByteStreams.toByteArray(inputStream);
ByteStreams
ile açıklama eklendi@Beta
Her zaman olduğu gibi, Bahar çerçevesinin de (3.2.2'den beri bahar çekirdeği) sizin için bir şeyleri var: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();
}
Güvenli çözüm (close
doğru akış akışı ile):
Java 9+ sürümü:
final byte[] bytes;
try (inputStream) {
bytes = inputStream.readAllBytes();
}
Java 8 sürümü:
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 sürümü (Java 9+ erişilebilir olmadığında):
@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()
}
}
İç içe geçmekten kaçınmak use
için buraya bakın .
Görüntüye gerçekten ihtiyacınız var byte[]
mı? Tam olarak ne bekliyorsunuz byte[]
- görüntü dosyasının içinde bulunduğu formatta kodlanmış bir görüntü dosyasının veya RGB piksel değerlerinin tam içeriği?
Buradaki diğer yanıtlar, bir dosyanın nasıl okunacağını gösterir byte[]
. Dosyanız byte[]
içeriğin tam içeriğini içerecektir ve görüntü verileriyle herhangi bir şey yapmak için bunu çözmeniz gerekir.
Java'nın görüntüleri okumak (ve yazmak) için standart API'si, pakette bulabileceğiniz ImageIO API'sıdır javax.imageio
. Bir görüntüden yalnızca tek bir kod satırı ile bir görüntüde okuyabilirsiniz:
BufferedImage image = ImageIO.read(new File("image.jpg"));
Bu size a verir BufferedImage
, a değil byte[]
. Görüntü verilerine getRaster()
ulaşmak için BufferedImage
. Bu size Raster
piksel verilerine erişmek için yöntemleri olan bir nesne verecektir (birkaç getPixel()
/ getPixels()
yöntemi vardır).
API belgelerini arama için javax.imageio.ImageIO
, java.awt.image.BufferedImage
, java.awt.image.Raster
vb
ImageIO varsayılan olarak bir dizi görüntü formatını destekler: JPEG, PNG, BMP, WBMP ve GIF. Daha fazla biçim için destek eklemek mümkündür (ImageIO servis sağlayıcı arayüzünü uygulayan bir eklentiye ihtiyacınız vardır).
Ayrıca aşağıdaki eğiticiye bakın: Görüntülerle Çalışma
Birisi hala bağımlılığı olmayan bir çözüm arıyor ve bir dosyanız varsa .
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);
Apache ortak kitaplığını kullanmak istemiyorsanız, bu pasaj sun.misc.IOUtils sınıfından alınır. ByteBuffers kullanan ortak uygulamanın neredeyse iki katıdır:
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: Tampondan tamamen kaçınabilirsiniz.
Kod http://www.exampledepot.com/egs/java.io/File2ByteArray.html adresinden kopyalandı (Evet, çok ayrıntılı, ancak diğer çözüm olarak belleğin yarısının boyutuna ihtiyacı var.)
// 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()
eğer offset < bytes.length
yoksa InputStream
o istisnası atılır eğer kapalı olmayacak.
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
bir de BufferedInputStream
OS-aramaları azaltmak ve önemli ölçüde performans dezavantajları telafi edeceğini kodundan önce, bu kod yine başka bir tampon gereksiz manuel kopyalama işleri yapacaktır.
Java 9 nihayet size güzel bir yöntem verecektir:
InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();
InputStram.readAllBytes()
tek astar arasındaki fark nedir ?
Çok geç olduğunu biliyorum ama burada daha okunabilir olan daha temiz bir çözüm olduğunu düşünüyorum ...
/**
* 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 yolu ( BufferedReader ve Adam Bien sayesinde )
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>);
}
}
Not Bu çözeltiye silme bezlerinin bir satır başı ( '\ R') ve uygunsuz olabilir.
String
. OP istiyor byte[]
.
\r
bir sorun değil. Bu yöntem, baytları karakterlere ve tekrar geri dönüştürür (InputStreamReader için varsayılan karakter kümesini kullanarak). Varsayılan karakter kodlamasında geçerli olmayan tüm baytlar (diyelim ki Linux'ta UTF-8 için -1), baytların sayısını bile değiştirebilir.
Çöp verilerini yazmak için bir düzeltme ile @ numan'ın cevabını düzenlemeye çalıştım, ancak düzenleme reddedildi. Bu kısa kod parçası parlak bir şey olmasa da, daha iyi bir cevap göremiyorum. Benim için en anlamlı olan şey:
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 öğesinin kapatılması gerekmez. okunabilirlik için atlanmıştır
InputStream.available()
Belgelere bakın :
Kapsayıcı boyutlandırmak için bu yöntemi kullanmamanız gerektiğini ve kapsayıcıyı yeniden boyutlandırmaya gerek kalmadan akışın tamamını okuyabileceğinizi varsaymanız özellikle önemlidir. Bu tür arayanlar muhtemelen okudukları her şeyi bir ByteArrayOutputStream öğesine yazmalı ve bunu bir bayt dizisine dönüştürmelidir. Alternatif olarak, bir dosyadan okuyorsanız, File.length dosyanın geçerli uzunluğunu döndürür (dosyanın uzunluğunun değişemeyeceğini varsayarsak, bir dosyayı okumak doğal olarak açıktır).
Herhangi bir nedenden ötürü masanın dışındaysa bir DataInputStream içine sarın, sadece -1 veya istediğiniz tüm bloğu verene kadar çekiçle okumak için kullanın.
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;
}
S3 nesnesini ByteArray'e dönüştürürken birkaç AWS işlemi için biraz gecikme görüyoruz.
Not: S3 Nesnesi PDF belgesidir (maksimum boyut 3 mb'dir).
S3 nesnesini ByteArray'e dönüştürmek için # 1 seçeneğini (org.apache.commons.io.IOUtils) kullanıyoruz. S3'ün S3 nesnesini ByteArray'e dönüştürmek için inbuild IOUtils yöntemini sağladığını fark ettik, gecikmeyi önlemek için S3 nesnesini ByteArray'e dönüştürmenin en iyi yolunun ne olduğunu onaylamanızı rica ediyoruz.
Seçenek 1:
import org.apache.commons.io.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);
Seçenek 2:
import com.amazonaws.util.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);
Ayrıca s3 nesnesini bytearray'a dönüştürmek için daha iyi bir yolumuz varsa bize bildirin
Diğer durum, sunucuya istek gönderdikten ve yanıtı bekledikten sonra akış yoluyla doğru bayt dizisini almak için.
/**
* 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);
ByteArrayOutputStream kullanıyorsanız ekstra bir kopya yapıyorsunuz. Akışın okumaya başlamadan önce uzunluğunu biliyorsanız (örneğin, InputStream aslında bir FileInputStream'dir ve dosyada file.length () yöntemini çağırabilirsiniz veya InputStream, InputStream adlı bir zipfile girdisidir ve zipEntry öğesini çağırabilirsiniz. length ()) kullanırsanız, doğrudan byte [] dizisine yazmak çok daha iyidir - belleğin yarısını kullanır ve zaman kazandırır.
// 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 akışı okunurken sen olma olasılığını işlemek gerekiyorsa, ancak dosya alırsa dosyalarla fırsatlar, kesilmiş alma yukarıdaki son satırı artık akışı okunurken, bayt içinde içindekiler [] dizi uzar olmayacak yeni dosya içeriğini dahil etmek için dizi basitçe eski inputStreamLength uzunluk girişine kısaltılacaktır .
Bunu kullanıyorum.
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();
}
}
Bu benim kopyala-yapıştır versiyonum:
@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 ve üstü:
import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);
sun.misc.IOUtils
"Java 7" değildir. Diğer JRE uygulamalarında bulunmayan ve sonraki sürümlerden herhangi birinde uyarı olmadan kaybolabilen tescilli, uygulamaya özel bir sınıftır.
Veri baytlarını mümkün olduğunca kopyalamaktan kaçınmaya çalışan optimize edilmiş bir sürüm:
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;
}
}
Kotlin'deki çözüm (elbette Java'da da çalışacaktır), her iki durumu da bildiğinizde veya bilmediğinizde:
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
}
}
Boyutu biliyorsanız, diğer çözümlere kıyasla kullanılan hafızanın iki katından tasarruf etmenizi sağlar (kısa bir süre içinde, ancak yine de yararlı olabilir). Bunun nedeni, tüm akışı sonuna kadar okumanız ve daha sonra bunu bir bayt dizisine (yalnızca bir diziye dönüştürdüğünüz ArrayList'e benzer) dönüştürmeniz gerektiğidir.
Örneğin, Android'de iseniz ve işlemek için bazı Uri'niz varsa, bunu kullanarak boyutu almaya çalışabilirsiniz:
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();
}