【发布时间】:2010-11-18 21:07:04
【问题描述】:
如何将整个InputStream 读入字节数组?
【问题讨论】:
-
看反面:byte[] 到 InputStream 这里:stackoverflow.com/questions/2091454/…
标签: java bytearray inputstream
如何将整个InputStream 读入字节数组?
【问题讨论】:
标签: java bytearray inputstream
您需要从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 并返回 byte[]。
InputStream is;
byte[] bytes = IOUtils.toByteArray(is);
这会在内部创建一个ByteArrayOutputStream 并将字节复制到输出,然后调用toByteArray()。它通过复制 4KiB 块中的字节来处理大文件。
【讨论】:
FastArrayList 这样的Apache commons 或者他们的软弱参考地图,然后回来告诉我这个库是多么“经过良好测试”。一堆垃圾
InputStream is;byte[] filedata=ByteStreams.toByteArray(is);
以下代码
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();
}
或
BufferedImage img = ...
ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
ImageIO.write(img, "jpeg", baos);
baos.flush();
byte[] result = baos.toByteArray();
baos.close();
【讨论】:
你真的需要byte[] 的图片吗?您对byte[] 的期望究竟是什么——图像文件的完整内容,以图像文件的任何格式编码,还是 RGB 像素值?
此处的其他答案向您展示如何将文件读入byte[]。您的 byte[] 将包含文件的确切内容,您需要对其进行解码才能对图像数据执行任何操作。
Java 用于读取(和写入)图像的标准 API 是 ImageIO API,您可以在包 javax.imageio 中找到它。您只需一行代码即可从文件中读取图像:
BufferedImage image = ImageIO.read(new File("image.jpg"));
这将为您提供BufferedImage,而不是byte[]。要获取图像数据,您可以拨打BufferedImage 上的getRaster()。这将为您提供一个Raster 对象,该对象具有访问像素数据的方法(它有几个getPixel() / getPixels() 方法)。
查找javax.imageio.ImageIO、java.awt.image.BufferedImage、java.awt.image.Raster 等的 API 文档
ImageIO 默认支持多种图像格式:JPEG、PNG、BMP、WBMP 和 GIF。可以添加对更多格式的支持(您需要一个实现 ImageIO 服务提供者接口的插件)。
另请参阅以下教程:Working with Images
【讨论】:
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 包装在 BufferedInputStream 之前,该代码会减少操作系统调用并显着减轻性能缺陷,但该代码仍会执行从一个缓冲区到另一个缓冲区的不必要的手动复制工作。
/*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();
}
【讨论】:
@Adamski:你可以完全避免缓冲。
从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;
}
【讨论】:
offset < bytes.length 则应添加is.close(),否则如果抛出该异常,InputStream 将不会关闭。
使用 vanilla Java 的 DataInputStream 及其 readFully 方法(至少从 Java 1.4 开始存在):
...
byte[] bytes = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(bytes);
...
此方法还有其他一些风格,但我一直在此用例中使用它。
【讨论】:
DataInputStream 类主要用于从流中读取主要类型(Longs、Shorts、Chars...),因此我们可以将这种用法视为对类的滥用。
InputStream.read好。
我尝试使用写入垃圾数据的修复程序来编辑 @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();
btw ByteArrayOutputStream 不需要关闭。为便于阅读,省略了 try/finally 结构
【讨论】:
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();
【讨论】:
如果你碰巧用了Google Guava,那就和ByteStreams一样简单:
byte[] bytes = ByteStreams.toByteArray(inputStream);
【讨论】:
如果你不想使用 Apache commons-io 库,这个 sn-p 取自 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);
注意上面的最后一行处理在读取流时文件被截断,如果您需要处理这种可能性,但是如果在读取流时文件变得 longer,则字节 [ ] 数组不会被加长以包含新的文件内容,数组只会被截断为旧长度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;
}
编码字符串()
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;
}
【讨论】:
String,然后转换为byte[](这可能会混淆二进制数据)? ByteArrayOutputStream 有 .toByteArray(): docs.oracle.com/javase/7/docs/api/java/io/…
请参阅InputStream.available() 文档:
意识到你不能使用这个是特别重要的 方法来调整容器的大小并假设您可以阅读全部内容 流,而无需调整容器的大小。这样的来电者 可能应该将他们读取的所有内容写入 ByteArrayOutputStream 并将其转换为字节数组。或者,如果您正在阅读 从文件中,File.length 返回文件的当前长度 (虽然假设文件的长度不能改变可能是不正确的, 读取文件本质上是活泼的)。
【讨论】:
我用这个。
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);
【讨论】:
sun.misc.IOUtils 不是“Java 7”。它是一个专有的、特定于实现的类,可能不存在于其他 JRE 实现中,并且可以在下一个版本中消失而不会发出任何警告。
终于,在 20 年后,有一个不需要 3rd 方库的简单解决方案,感谢Java 9:
InputStream is;
…
byte[] array = is.readAllBytes();
还要注意readNBytes(byte[] b, int off, int len) 和transferTo(OutputStream) 解决重复性需求的便捷方法。
【讨论】:
InputStream 是否覆盖readAllBytes() 或readNBytes?
如果由于某种原因不在表格中,请将其包装在 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();
【讨论】:
InputStram.readAllBytes()那是单线有什么区别?
ByteArrayOutputStream 中肯定有很多数组调整大小,然后是数据的完整副本。
与往常一样,Spring framework(自 3.2.2 以来的 spring-core)也为您提供了一些东西:StreamUtils.copyToByteArray()
【讨论】:
如果有人仍在寻找没有依赖关系的解决方案并且如果您有文件。
数据输入流
byte[] data = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(data);
dis.close();
字节数组输出流
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 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')并且可能不合适。
【讨论】:
String。 OP 要求byte[]。
\r 可能是个问题。此方法将字节转换为字符并再次转换回来(使用 InputStreamReader 的默认字符集)。任何在默认字符编码中无效的字节(例如,Linux 上的 UTF-8 为 -1)都将被损坏,甚至可能更改字节数。
你可以试试Cactoos:
byte[] array = new BytesOf(stream).bytes();
【讨论】:
在将 S3 对象转换为 ByteArray 时,我们看到一些 AWS 事务出现延迟。
注意:S3 对象是 PDF 文档(最大大小为 3 mb)。
我们使用选项 #1 (org.apache.commons.io.IOUtils) 将 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 对象转换为字节数组,请告诉我
【讨论】: