将OutputStream转换为InputStream

2025/04/06

1. 概述

InputStream和OutputStream是Java IO中的两个基本类。有时,我们需要在这两种流类型之间进行转换。在之前的教程中,我们讨论了如何将InputStream写入OutputStream。

在本快速教程中,我们将探索如何将OutputStream转换为InputStream。

2. 问题介绍

有时,需要将OutputStream转换为InputStream,这种转换在很多情况下都很有用,例如当我们需要读取已写入OutputStream的数据时

在本文中,我们将探讨执行此转换的两种不同方法:

  • 使用字节数组
  • 使用管道

为简单起见,我们将在示例中使用ByteArrayOutputStream作为OutputStream类型。此外,我们将使用单元测试断言来验证是否可以从转换后的InputStream对象中读取预期数据。

接下来让我们看看它们的实际效果。

3. 使用字节数组

当我们思考这个问题时,最直接的方法可能是:

接下来,让我们将这个想法作为测试来实现,并检查它是否按预期工作:

@Test
void whenUsingByteArray_thenGetExpectedInputStream() throws IOException {
    String content = "I'm an important message.";
    try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
        out.write(content.getBytes());
        try (ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray())) {
            String inContent = new String(in.readAllBytes());

            assertEquals(content, inContent);
        }
    }
}

首先,我们准备一个OutputStream对象(out)并向其中写入一个字符串(content)。接下来,我们通过调用out.toByteArray()从OutputStream中获取字节数组形式的数据,并从该数组创建一个InputStream。

如果我们运行测试,它就会通过,因此转换成功。

值得一提的是,我们使用了try-with-resources来确保在读取和写入操作后关闭InputStream和OutputStream。此外,我们的try块没有catch块,因为我们已经声明测试方法会抛出IOException。

这种方法简单易行,但是缺点是它需要将整个输出存储在内存中,然后才能将其读回作为输入。换句话说,如果输出非常大,可能会导致大量内存消耗,并可能导致OutOfMemoryError

4. 通过管道

我们经常一起使用PipedOutputStream和PipedInputStream类来将数据从OutputStream传递到InputStream。因此,我们可以先连接PipedOutputStream和PipedInputStream,以便PipedInputStream可以读取来自PipedOutputStream的数据。接下来,我们可以将给定的OutputStream的数据写入PipedOutputStream。然后,在另一端,我们可以从PipedInputStream读取数据。

接下来,让我们将其作为单元测试来实现:

@Test
void whenUsingPipeStream_thenGetExpectedInputStream() throws IOException {
    String content = "I'm going through the pipe.";

    ByteArrayOutputStream originOut = new ByteArrayOutputStream();
    originOut.write(content.getBytes());

    //connect the pipe
    PipedInputStream in = new PipedInputStream();
    PipedOutputStream out = new PipedOutputStream(in);

    try (in) {
        new Thread(() -> {
            try (out) {
                originOut.writeTo(out);
            } catch (IOException iox) {
                // ...
            }
        }).start();

        String inContent = new String(in.readAllBytes());
        assertEquals(content, inContent);
    }
}

如上面的代码所示,首先我们准备好OutputStream(originOut),然后我们创建PipedInputStream(in)和PipedOutputStream(out),并将它们连接起来,这样就建立了一个管道。

然后,我们使用ByteArrayOutputStream.writeTo()方法将数据从给定的OutputStream转发到PipedOutputStream。我们应该注意,我们创建了一个新线程来将数据写入PipedOutputStream,这是因为不建议在同一个线程中同时使用PipedInputStream和PipedOutputStream对象,这可能会导致死锁

最后,如果我们执行它,测试就会通过。因此,OutputStream已成功转换为PipedInputStream。

5. 总结

在本文中,我们探讨了将OutputStream转换为InputStream的两种方法:

  • 字节数组作为缓冲区:这很简单,但是它有OutOfMemoryError的潜在风险
  • 使用管道:将输出写入PipedOutputStream使数据流向PipedInputStream
Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章