将InputStream转换为Java中的字节数组

如何将整个InputStream读取到字节数组中?

1144442 次浏览

您需要从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共享资源IO来处理此任务和类似任务。

IOUtils类型有一个静态方法来读取InputStream并返回byte[]

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();}

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.ImageIOjava.awt.image.BufferedImagejava.awt.image.Raster等的API留档。

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 DBclass_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 & InputStreamIn 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 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 = new byte[(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) {throw new IOException("Could not completely read file "+file.getName());}
// Close the input stream and return bytesis.close();return bytes;}

使用vanillaJava的DataInputStream及其readFully方法(至少Java1.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 sizeint length;
while ((length = in.read(buffer)) != -1) out.write(buffer, 0, length); //copy streamsin.close(); // call this in a finally block
byte[] result = out.toByteArray();

btw ByteArrayOutputStream不需要被关闭. try/最终构造为易读性而省略

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();

如果你碰巧使用googleguava,它将像使用ByteStreams一样简单:

byte[] bytes = ByteStreams.toByteArray(inputStream);

如果您不想使用Apache Commons-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 roombytesToRead = 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 expectedSizeif (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 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();}

另一种情况是在向服务器发送请求并等待响应后,通过流获取正确的字节数组。

/*** 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 thefollowing byte array which initialised with accepted data length. */DataInputStream mDis = new DataInputStream(mSocket.getInputStream());byte[] data = new byte[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 = new String(data);

如果你在开始读取之前就知道流的长度(例如InputStream实际上是一个FileInputStream,你可以在文件上调用file.length(),或者InputStream是一个zipfile条目InputStream,你可以调用zipEntry.length()),那么直接写入byte[]数组会更好-它使用一半的内存,并节省时间。

// Read the file contents into a byte[] arraybyte[] 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 operationbyte[] contents = bytesRead == inputStreamLength ? buf: Arrays.copyOf(buf, bytesRead);

注意:上面的最后一行处理文件在读取流时被截断,如果你需要处理这种可能性,但是如果文件在读取流时获得更长,byte[]数组中的内容不会被加长以包含新文件内容,数组将简单地截断为旧长度输入流长度

这对我有用,

if(inputStream != null){ByteArrayOutputStream contentStream = readSourceContent(inputStream);String stringContent = contentStream.toString();byte[] byteArr = encodeString(stringContent);}

//读取源内容//读取源内容

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;}

codeString()//编码方式

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()留档:

特别重要的是要意识到你不能使用这个方法来调整容器的大小,并假设您可以读取整个容器的流,而无需调整容器的大小。这样的调用者应该把读到的所有东西都写到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();}

Java7及以后:

import sun.misc.IOUtils;...InputStream in = ...;byte[] buf = IOUtils.readFully(in, -1, false);

最后,二十年后,有一个简单的解决方案,不需要第三方库,感谢Java9

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;}

Java9最终会给你一个很好的方法:

InputStream in = ...;ByteArrayOutputStream bos = new ByteArrayOutputStream();in.transferTo( bos );byte[] bytes = bos.toByteArray();

与往常一样,Spring框架(3.2.2开始的sping-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);

Java8路(感谢BufferedReaderadambien

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')并且可能不合适。

您可以尝试仙人掌

byte[] array = new BytesOf(stream).bytes();

在将S3对象转换为ByteArray时,我们看到一些AWS交易出现了一些延迟。

注意:S3对象是PDF文档(最大大小为3 MB)。

我们正在使用选项#1(org.apache.commons.io.IOUtils)将S3对象转换为ByteArray。我们注意到S3提供了inbuild 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对象到字节数组

安全解决方案(正确关闭流):

  • Java9及更新:

     final byte[] bytes;try (inputStream) {bytes = inputStream.readAllBytes();}

  • Java8岁及以上:

     public static byte[] readAllBytes(InputStream inputStream) throws IOException {final int bufLen = 4 * 0x400; // 4KBbyte[] 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);}}}

  • 静态编程语言(当Java9+无法访问时):

     @Throws(IOException::class)fun InputStream.readAllBytes(): ByteArray {val bufLen = 4 * 0x400 // 4KBval 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()}}

    要避免嵌套use,请参阅此处的


  • Scala(当Java9+无法访问时)(按@刘琼. thx):

    def readAllBytes(inputStream: InputStream): Array[Byte] =Stream.continually(inputStream.read).takeWhile(_ != -1).map(_.toByte).toArray

静态编程语言的解决方案(当然也适用于Java),其中包括您是否知道大小的两种情况:

    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)breakoffset += readif (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@useval 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.fileval 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)breakval skip = inputStream.skip(available.toLong())if (skip < 0)breakbytesCount += skip}if (bytesCount > 0L)return bytesCount}}return -1L}

您可以使用仙人掌库提供可重用的面向对象Java组件。该库强调OOP,因此没有静态方法、NULL等,只有真实物体及其契约(接口)。像读取输入流这样的简单操作,可以这样执行

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。在这种情况下,您将使用装饰图案并在Base64的实现中包装Bytes对象。仙人掌已经提供了这样的实现:

final Bytes encoded = new BytesBase64(new BytesOf(new InputStreamOf("XYZ")));Assert.assertEquals(new TextOf(encoded).asString(), "WFla");

您可以使用装饰器模式以相同的方式解码它们

final Bytes decoded = new Base64Bytes(new BytesBase64(new BytesOf(new InputStreamOf("XYZ"))));Assert.assertEquals(new TextOf(decoded).asString(), "XYZ");

无论您的任务是什么,您都可以创建自己的Bytes实现来解决它。

您可以使用仙人掌(我是它的开发人员之一):

import org.cactoos.bytes.BytesOf;byte[] array = new BytesOf(stream).asBytes();

您还可以将流转换为String

import org.cactoos.text.TextOf;String txt = new TextOf(stream).asString();

asBytes()asString()方法都抛出选中的Exception。如果您不想捕获它,请使用Unchecked*装饰器,例如:

import org.cactoos.bytes.BytesOf;import org.cactoos.bytes.UncheckedBytes;byte[] array = new UncheckedBytes(new BytesOf(stream)).asBytes();