如何将整个输入流读到字节数组?
您需要从InputStream中读取每个字节,并将其写入ByteArrayOutputStream。
然后你可以通过调用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();
您可以使用Apache Commons IO来处理这个任务和类似的任务。
IOUtils类型有一个静态方法来读取InputStream并返回一个字节[]。
InputStream is;
byte[] bytes = IOUtils.toByteArray(is);
这将在内部创建一个ByteArrayOutputStream并将字节复制到输出,然后调用toByteArray()。它通过以4KiB为块复制字节来处理大文件。
下面的代码
public static byte[] serializeObj(Object obj) throws IOException {
ByteArrayOutputStream baOStream = new ByteArrayOutputStream();
ObjectOutputStream objOStream = new ObjectOutputStream(baOStream);
objOStream.writeObject(obj);
objOStream.flush();
objOStream.close();
return baOStream.toByteArray();
}
OR
BufferedImage img = ...
ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
ImageIO.write(img, "jpeg", baos);
baos.flush();
byte[] result = baos.toByteArray();
baos.close();
你真的需要图像作为字节[]吗?你在字节[]中到底期望什么-图像文件的完整内容,以图像文件的任何格式编码,或RGB像素值?
这里的其他答案向您展示了如何将文件读入字节[]。您的字节[]将包含文件的确切内容,并且您需要对其进行解码才能对图像数据进行处理。
用于读取(和写入)图像的Java标准API是ImageIO API,您可以在javax.imageio包中找到它。你可以用一行代码从文件中读入一张图片:
BufferedImage image = ImageIO.read(new File("image.jpg"));
这将给您一个BufferedImage,而不是一个字节[]。要获取图像数据,可以在BufferedImage上调用getRaster()。这将为您提供一个光栅对象,该对象具有访问像素数据的方法(它有几个getPixel() / getPixels()方法)。
查找javax.imageio的API文档。ImageIO java.awt.image。BufferedImage, java。awt。image。raster等等。
ImageIO默认支持多种图像格式:JPEG, PNG, BMP, WBMP和GIF。可以添加对更多格式的支持(您需要一个实现ImageIO服务提供程序接口的插件)。
另请参阅下面的教程:使用图像
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 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();
}
你可以完全避免缓冲。
从http://www.exampledepot.com/egs/java.io/File2ByteArray.html复制的代码(是的,它非常冗长,但需要的内存大小是其他解决方案的一半)。
// 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;
}
使用普通Java的DataInputStream和它的readFully方法(至少从Java 1.4开始存在):
...
byte[] bytes = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(bytes);
...
这个方法还有其他一些形式,但在这个用例中,我一直使用这个方法。
我试图编辑@numan的答案,修复了写垃圾数据,但编辑被拒绝。虽然这段简短的代码并不出色,但我看不到其他更好的答案。以下是我认为最有意义的建议:
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();
ByteArrayOutputStream不需要关闭。为了可读性,省略了一些结构
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();
}
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();
如果你碰巧使用谷歌Guava,它将像使用ByteStreams一样简单:
byte[] bytes = ByteStreams.toByteArray(inputStream);
如果您不想使用Apache common -io库,则此代码片段取自sun.misc.IOUtils类。它的速度几乎是使用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;
}
下面是一个优化的版本,尽量避免复制数据字节:
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;
}
}
我知道已经太迟了,但我认为这里有更清晰的解决方案,更易于阅读……
/**
* 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();
}
另一种情况是在发送请求到服务器并等待响应后,通过流获得正确的字节数组。
/**
* 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,你会做一个额外的拷贝。如果你在开始读取流之前知道它的长度(例如,InputStream实际上是FileInputStream,你可以在文件上调用file.length(),或者InputStream是一个zipfile条目InputStream,你可以调用zipEntry.length()),那么直接写入byte[]数组会更好——它使用一半的内存,并节省时间。
// 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);
注意:上面的最后一行处理的是在读取流时被截断的文件,如果你需要处理这种可能性,但是如果在读取流时文件变长了,byte[]数组中的内容将不会被延长以包括新的文件内容,数组将简单地被截断为旧的长度inputStreamLength。
这对我很有用,
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;
}
请参阅InputStream.available()文档:
It is particularly important to realize that you must not use this method to size a container and assume that you can read the entirety of the stream without needing to resize the container. Such callers should probably write everything they read to a ByteArrayOutputStream and convert that to a byte array. Alternatively, if you're reading from a file, File.length returns the current length of the file (though assuming the file's length can't change may be incorrect, reading a file is inherently racy).
我用这个。
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();
}
}
这是我的复制粘贴版本:
@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及以上版本:
import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);
20年后,终于有了一个不需要第三方库的简单解决方案,这要感谢Java 9:
InputStream is;
…
byte[] array = is.readAllBytes();
还要注意方便的方法readNBytes(byte[] b, int off, int len)和transferTo(OutputStream)来解决重复的需求。
如果由于某种原因,它不在表中,则将其包装在DataInputStream中,只需使用read来锤击它,直到它给您一个-1或您所要求的整个块。
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;
}
Java 9最终会给你一个很好的方法:
InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();
如果有人还在寻找一个没有依赖的解决方案,如果你有一个文件。
DataInputStream
byte[] data = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(data);
dis.close();
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);
}
RandomAccessFile
RandomAccessFile raf = new RandomAccessFile(file, "r");
byte[] data = new byte[(int) raf.length()];
raf.readFully(data);
Java 8方式(感谢BufferedReader和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>);
}
}
注意,这个解决方案删除回车符('\r'),可能是不合适的。
在将S3对象转换为ByteArray时,我们看到一些AWS事务的延迟。
注意:S3对象为PDF文档(最大大小为3mb)。
我们使用选项#1将S3对象转换为ByteArray。我们注意到S3提供了内置IOUtils方法来将S3对象转换为ByteArray,我们请求您确认将S3对象转换为ByteArray的最佳方法以避免延迟。
选项1:
import org.apache.commons.io.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);
选项2:
import com.amazonaws.util.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);
也让我知道,如果我们有任何其他更好的方法来转换s3对象到bytearray
安全解决方案(正确关闭流):
Java 9及更新版本: 最终字节[]字节; try (inputStream) { 字节= inputStream.readAllBytes(); }
Java 8 and older: 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(当Java 9+不可访问时): @Throws (IOException::类) fun InputStream.readAllBytes(): ByteArray { val bufLen = 4 * 0x400 // 4KB val buf = ByteArray(bufLen) var readLen: Int = 0 ByteArrayOutputStream()。使用{o -> 这一点。使用{I -> i.read(buf, 0, bufLen)。{readLen = it} != -1) o.write(buf, 0, readLen) } 返回o.toByteArray () } } 避免嵌套使用请看这里。
Scala(当Java 9+不可访问时)(By @Joan。Thx): def readAllBytes(inputStream: inputStream): Array[Byte] = Stream.continually (read)。takeWhile(_ != -1).map(_. tobyte).toArray . take (_
Kotlin中的解决方案(当然也可以在Java中工作),其中包括当你知道大小时的两种情况:
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
}
}
如果您知道大小,那么与其他解决方案相比,它可以节省两倍的内存(在很短的时间内,但仍然可能有用)。这是因为您必须将整个流读到末尾,然后将其转换为字节数组(类似于将数组转换为数组的ArrayList)。
例如,如果你在Android上,你有一些Uri要处理,你可以尝试用这个来获取大小:
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
}
您可以使用cactoos库提供可重用的面向对象的Java组件。 这个库强调OOP,因此没有静态方法、null等等,只有真实对象及其契约(接口)。 像读取InputStream这样的简单操作可以这样执行
final InputStream input = ...;
final Bytes bytes = new BytesOf(input);
final byte[] array = bytes.asBytes();
Assert.assertArrayEquals(
array,
new byte[]{65, 66, 67}
);
使用专用类型Bytes来处理数据结构byte[]使我们能够使用OOP策略来解决手头的任务。 一些程序性的“效用”方法将禁止我们做的事情。 例如,您需要将从此InputStream读取的字节封装到Base64。 在本例中,您将使用Decorator模式并在Base64的实现中封装Bytes对象。 Cactoos已经提供了这样的实现:
final Bytes encoded = new BytesBase64(
new BytesOf(
new InputStreamOf("XYZ")
)
);
Assert.assertEquals(new TextOf(encoded).asString(), "WFla");
您可以使用Decorator模式以同样的方式解码它们
final Bytes decoded = new Base64Bytes(
new BytesBase64(
new BytesOf(
new InputStreamOf("XYZ")
)
)
);
Assert.assertEquals(new TextOf(decoded).asString(), "XYZ");
无论你的任务是什么,你都可以创建自己的Bytes实现来解决它。
你可以使用Cactoos(我是它的开发者之一):
import org.cactoos.bytes.BytesOf;
byte[] array = new BytesOf(stream).asBytes();
你也可以将流转换为字符串:
import org.cactoos.text.TextOf;
String txt = new TextOf(stream).asString();
asBytes()和asString()方法都会抛出checked Exception。如果你不想捕获它,使用Unchecked*装饰器,例如:
import org.cactoos.bytes.BytesOf;
import org.cactoos.bytes.UncheckedBytes;
byte[] array = new UncheckedBytes(new BytesOf(stream)).asBytes();
推荐文章
- 到底是什么导致了堆栈溢出错误?
- 为什么Android工作室说“等待调试器”如果我不调试?
- Java:路径vs文件
- ExecutorService,如何等待所有任务完成
- Maven依赖Servlet 3.0 API?
- 如何在IntelliJ IDEA中添加目录到应用程序运行概要文件中的类路径?
- getter和setter是糟糕的设计吗?相互矛盾的建议
- Android room persistent: AppDatabase_Impl不存在
- Java的String[]在Kotlin中等价于什么?
- Intellij IDEA上的System.out.println()快捷方式
- 使用Spring RestTemplate获取JSON对象列表
- Spring JPA选择特定的列
- URLEncoder不能翻译空格字符
- Java中的super()
- 如何转换JSON字符串映射<字符串,字符串>与杰克逊JSON