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

JGC*_*JGC 814 java bytearray inputstream

如何将整个读InputStream入字节数组?

Ric*_*ler 1095

您可以使用Apache Commons IO来处理此类和类似的任务.

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

InputStream is;
byte[] bytes = IOUtils.toByteArray(is);
Run Code Online (Sandbox Code Playgroud)

在内部,这会创建一个ByteArrayOutputStream并将字节复制到输出,然后调用toByteArray().它通过复制4KiB块中的字节来处理大文件.

  • @oxbow_lakes:考虑到我在开发人员生活中看到的这个功能的**错误**实现的惊人数量,我觉得**是**非常*非常值得外部依赖来实现它. (234认同)
  • 如果有一个库来处理需求,并处理大型文件的处理,并且经过了充分的测试,那么问题是我为什么要自己编写呢?jar只有107KB,如果你需要一个方法,你也可能会使用其他方法 (207认同)
  • 想要编写4行代码,您认为导入第三方依赖是否值得? (183认同)
  • 除了Apache commons-io之外,请查看[ByteStreams](http://docs.guava-libraries.googlecode.com/git-history/v10.0.1/javadoc/com/google/common/io/ByteStreams.html )来自[Google Guava]的课程(http://code.google.com/p/guava-libraries/).`InputStream是;``byte [] filedata = ByteStreams.toByteArray(是);` (83认同)
  • 为什么不去看看像"FastArrayList"这样的Apache公共资源或者它们的软弱参考地图,然后回过头来告诉我这个库是如何"经过充分测试"的.这是一堆垃圾 (17认同)
  • 为了回应"去看看Apache公共事物,比如FastArrayList或者它们的软弱参考地图",然后回来告诉我这个库是如何"经过良好测试的"......这就像说"品尝那些布鲁塞尔豆芽和告诉我这些西红柿有多好".如果我把这些西红柿添加到我的菜中,品尝它,就像它和其他人显然也喜欢它一样,那么我对来自同一家杂货店的布鲁塞尔豆芽的关注是什么呢? (4认同)
  • 为了读取流而拉入整个库总结了Java开发的整体问题. (4认同)
  • @Nayn:使用第三方解决方案的问题首先是假设第三方开发人员比你聪明,只是因为他们正在编写第三方库或第三方库的代码"经过良好测试",仅仅因为它居住在第三方图书馆.而且,通常,它不是第三方库依赖,而是十几个,因为这些第三方库是由开发人员编写的,他们也不关心最小化第三方库依赖性.Java开发人员倾向于更多地了解第三方库而不是标准API. (3认同)
  • 这个用例有"DataInputStream"及其方法"readFully" - 不需要外部库和带有幻数的奇怪循环. - 请参阅下面的答案 (2认同)
  • 不使用经过时间考验的 3rd-party 依赖项的唯一原因是因为您很懒惰和/或没有使用最佳实践。使用像 Maven 这样的依赖管理工具,然后是的,这是值得的。 (2认同)
  • @cytinus,懒惰是我不必编写/维护它,而不是其他方式。在学校:全面实施,在工作:第三方。 (2认同)
  • `IOUtils.toByteArray(InputStream)`只能以4KB的块复制,而不是4MB.在IOUtils.java中,块大小定义为`private static final int DEFAULT_BUFFER_SIZE = 1024*4`. (2认同)
  • @JoachimSauer你正是为了使用第三方库而已.我刚刚完成了整整两天的工作,只是为了弄清楚某人是否严重执行了字节数组转换.使用IOUtils我可以摆脱这个问题.投票给你答案和评论;) (2认同)
  • 不建议使用此方法。你能更新答案吗? (2认同)
  • @KevinMeredith 从 Java 9 开始,现在有一种内置的方法可以做到这一点。参见 [Holger 的回答](/sf/answers/2637692571/)。 (2认同)

Ada*_*ski 439

您需要从您的每个字节读取InputStream并将其写入a 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();
Run Code Online (Sandbox Code Playgroud)

  • 新创建的byte []的大小怎么样?为什么是16384?我怎样才能确定合适的尺寸?非常感谢你. (15认同)
  • 16384是一个相当随意的选择,虽然我倾向于支持2的幂来增加数组与字边界对齐的机会.pihentagy的答案显示了如何避免使用中间缓冲区,而是分配一个正确大小的数组.除非你正在处理大文件,否则我个人更喜欢上面的代码,它更优雅,可以用于InputStreams,其中预先知道要读取的字节数. (6认同)
  • @Adamski许多基础设施硬件,网络服务器和操作系统层组件都使用4K缓冲区来移动数据,这就是确切数字的原因,但重点是你通过4K来获得如此小的性能提升它通常被认为是浪费内存.我假设这仍然是*真的,因为它有十年前的知识! (5认同)

Hol*_*ger 280

最后,二十年后,有了一个简单的解决方案,而不需要第三方库,这要归功于Java 9:

InputStream is;
…
byte[] array = is.readAllBytes();
Run Code Online (Sandbox Code Playgroud)

还要注意便利方法readNBytes(byte[] b, int off, int len)transferTo(OutputStream)解决重复需求.

  • @pdem 没有这样的限制。我刚刚通过将 2GiB 文件读入内存来验证它。只要可以分配适当大的数组,它就可以工作。如果您得到不同的结果,则表明您的测试设置有问题。您“不应该”将如此大的文件读入内存,而是更喜欢在读取时处理它们,这是完全不同的事情。它显然适用于问答中提出的所有解决方案,因为它们都是关于将整个文件读入内存的。 (4认同)
  • Java 文档“请注意,此方法适用于可以方便地将所有字节读入字节数组的简单情况。它不适用于读取具有大量数据的输入流。” 事实上,从我的测试来看,它被限制为 8192(未记录) 使用它进行测试,但不能在生产中使用。 (2认同)
  • 听起来本身就值得一个问题。 (2认同)

der*_*itz 126

使用vanilla Java DataInputStream及其readFully方法(至少从Java 1.4开始存在):

...
byte[] bytes = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(bytes);
...
Run Code Online (Sandbox Code Playgroud)

这种方法还有其他一些风格,但我一直都在使用这个用例.

  • +1用于使用标准库而不是第三方依赖项.不幸的是,它对我不起作用,因为我不知道前面的流的长度. (44认同)
  • 如果您已经知道要从流中读取的数据长度,那么这并不比`InputStream.read`好. (17认同)
  • @janus它是一个"文件".只有当你知道文件的长度或要读取的字节数时,这种方式才有效. (4认同)
  • 有趣的事情,但你必须知道要读取的(部分)流的确切长度.此外,类`DataInputStream`主要用于从流中读取主要类型(Longs,Shorts,Chars ...),因此我们可以将此用法视为对类的误用. (4认同)
  • 什么是imgFile?它不能是一个InputStream,它应该是这个方法的输入 (2认同)
  • @LoganPickup InputStream.read不保证返回您请求的所有字节! (2认同)
  • readFully在内部循环,直到拥有所需的字节为止。这比使用“ read”要方便得多,在“ read”中,您必须自己编写循环。所以我认为这更好。我只是用GZIPInputStream遇到了这种情况,在该调用中,读调用将仅返回所需字节的一小部分,并且readFully读取所有字节。在这两种情况下,我都知道要从流读取的数据长度。 (2认同)

ber*_*tie 116

如果您碰巧使用谷歌番石榴,它将如此简单:

byte[] bytes = ByteStreams.toByteArray(inputStream);
Run Code Online (Sandbox Code Playgroud)

  • `ByteStreams`用`@ Beta`注释 (6认同)

Arn*_*ter 42

和往常一样,Spring框架(自3.2.2以来的spring-core)也有适合你的东西:StreamUtils.copyToByteArray()

  • 和大多数其他人一样,我想避免使用第三方库来完成如此简单的事情,但 Java 9 目前不是一个选择……幸运的是,我已经在使用 Spring。 (2认同)

oli*_*rkn 40

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();
}
Run Code Online (Sandbox Code Playgroud)

  • 我理解一个例子中的简洁,但为什么不只是让示例方法抛出IOException而不是吞下它并返回一个毫无意义的值? (9认同)
  • 我冒昧地从'return null'改为'throw IOException' (4认同)
  • 这里不需要尝试使用资源,因为ByteArrayOutputStream #close()什么都不做.(ByteArrayOutputStream#flush()不需要也不做任何事情.) (3认同)
  • 这是一个例子,因此,简洁是一天的顺序.在某些情况下,在这里返回null也是正确的选择(尽管在生产环境中,您也可以使用适当的异常处理和文档). (2认同)

Jes*_*per 19

你真的需要这个形象byte[]吗?您对byte[]图像文件的完整内容有何期待- 以图像文件所处的格式编码,或RGB像素值?

这里的其他答案向您展示如何将文件读入byte[].您byte[]将包含文件的确切内容,并且您需要解码它以对图像数据执行任何操作.

Java用于读取(和写入)图像的标准API是ImageIO API,您可以在包中找到它javax.imageio.您只需一行代码即可从文件中读取图像:

BufferedImage image = ImageIO.read(new File("image.jpg"));
Run Code Online (Sandbox Code Playgroud)

这会给你一个BufferedImage,而不是一个byte[].要获取的图像数据,可以调用getRaster()BufferedImage.这将为您提供一个Raster对象,该对象具有访问像素数据的方法(它有几个getPixel()/ getPixels()方法).

查找API文档javax.imageio.ImageIO,java.awt.image.BufferedImage,java.awt.image.Raster等.

默认情况下,ImageIO支持多种图像格式:JPEG,PNG,BMP,WBMP和GIF.可以添加对更多格式的支持(您需要一个实现ImageIO服务提供程序接口的插件).

另请参阅以下教程:使用图像


Mir*_*ili 16

安全的解决方案(具有close正确的流功能):

  • Java 9+版本:

    final byte[] bytes;
    try (inputStream) {
        bytes = inputStream.readAllBytes();
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • Java 8版本:

    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);
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • Kotlin版本(无法访问Java 9+时):

    @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()
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    为避免嵌套,use请参见此处

  • java 8代码版本,也成功适用于java 1.7。 (2认同)

Kri*_*jic 14

如果您不想使用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 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;
}
Run Code Online (Sandbox Code Playgroud)


har*_*h_v 14

在某些情况下有人仍在寻找没有依赖关系的解决方案,如果你有一个文件.

1)DataInputStream

 byte[] data = new byte[(int) file.length()];
 DataInputStream dis = new DataInputStream(new FileInputStream(file));
 dis.readFully(data);
 dis.close();
Run Code Online (Sandbox Code Playgroud)

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);
 }
Run Code Online (Sandbox Code Playgroud)

3)RandomAccessFile

 RandomAccessFile raf = new RandomAccessFile(file, "r");
 byte[] data = new byte[(int) raf.length()];
 raf.readFully(data);
Run Code Online (Sandbox Code Playgroud)

  • 或者简单地说:byte [] data = Files.readAllBytes(file.toPath()); (2认同)

Yul*_*ney 10

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();
Run Code Online (Sandbox Code Playgroud)


小智 8

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();
Run Code Online (Sandbox Code Playgroud)

  • 一个字节可以成为性能杀手.真的. (22认同)
  • @Maarten Bodewes:大多数设备都有一种块传输,因此不是每个read()都会导致实际的设备访问,但是每个字节的OS调用已经足以破坏性能.虽然在该代码之前将`InputStream`包装在`BufferedInputStream`中会减少OS调用并显着降低性能缺陷,但该代码仍然会从一个缓冲区到另一个缓冲区进行不必要的手动复制工作. (6认同)

pih*_*agy 8

@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;
}
Run Code Online (Sandbox Code Playgroud)

  • 取决于提前了解大小. (5认同)
  • 那么更好的是,你应该使用try-with-resources (3认同)
  • 当然,但他们应该知道大小:"我想读一个图像" (2认同)

Chr*_*oom 5

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

InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();
Run Code Online (Sandbox Code Playgroud)

  • 这和单行的“InputStram.readAllBytes()”有什么区别? (4认同)