1. 概述

本文我们将学习如何将 InputStream 写入 OutputStream。我们先使用 Java 8、Java 9原生API实现,然后再演示通过第三方库 - Guava 以及 Apache Commons IO library 实现。

注意,Java 9、Guava 和 Apache Commons IO 提供的工具方法不会flush或关闭流。 因此,我们需要使用 try-with-resourcesfinally 块来管理这些资源。

2. 使用 Java 8

第一种方式,我们使用原生Java代码将 InputStream 内容拷贝到 OutputStream

void copy(InputStream source, OutputStream target) throws IOException {
    byte[] buf = new byte[8192];
    int length;
    while ((length = source.read(buf)) > 0) {
        target.write(buf, 0, length);
    }
}

这种方式很简单,我们按字节读取数据然后写入到OutputStream中。

3. 使用 Java 9

Java 9 新增了一个InputStream.transferTo()方法,能够实现我们的需求

@Test
public void givenUsingJavaNine_whenCopyingInputStreamToOutputStream_thenCorrect() throws IOException {
    String initialString = "Hello World!";

    try (InputStream inputStream = new ByteArrayInputStream(initialString.getBytes());
         ByteArrayOutputStream targetStream = new ByteArrayOutputStream()) {
        inputStream.transferTo(targetStream);

        assertEquals(initialString, new String(targetStream.toByteArray()));
    }
}

注意:在处理文件流的时候,使用 Files.copy() 比使用 transferTo() 方法更高效

4. 使用 Guava

下面,我们看下如何使用 Guava提供ByteStreams.copy()工具方法

首先需要在pom.xml中引入guava依赖:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>29.0-jre</version>
</dependency>

下面的测试示例中展示了如何使用 ByteStreams 拷贝数据:

@Test
public void givenUsingGuava_whenCopyingInputStreamToOutputStream_thenCorrect() throws IOException {
    String initialString = "Hello World!";

    try (InputStream inputStream = new ByteArrayInputStream(initialString.getBytes());
         ByteArrayOutputStream targetStream = new ByteArrayOutputStream()) {
        ByteStreams.copy(inputStream, targetStream);

        assertEquals(initialString, new String(targetStream.toByteArray()));
    }
}

5. 使用 Commons IO

最后,我们将使用 Commons IO 的IOUtils.copy()方法来完成这项任务。

pom.xml 中增加commons-io 依赖:

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.8.0</version>
</dependency>

IOUtils 使用示例:

@Test
public void givenUsingCommonsIO_whenCopyingInputStreamToOutputStream_thenCorrect() throws IOException {
    String initialString = "Hello World!";

    try (InputStream inputStream = new ByteArrayInputStream(initialString.getBytes());
         ByteArrayOutputStream targetStream = new ByteArrayOutputStream()) {
        IOUtils.copy(inputStream, targetStream);

        assertEquals(initialString, new String(targetStream.toByteArray()));
    }
}

备注: Commons IO 还提供了几个额外的方法处理 InputStream 和 OutputStream。**当需要拷贝的数据超过2GB的时候,应该使用IOUtils.copyLarge()**。

6. 总结

本文我们学习了如何从InputStream中复制数据到OutputStream的几种方法。

本文示例中的代码存放在 GitHub