如何将输出流转换为输入流?

2022-08-31 04:42:30

我正处于开发阶段,我有两个模块,从一个模块中,我得到了输出作为第二个模块,它只接受 。你知道如何转换为(反之亦然,我的意思是真的这样)我将能够连接这两个部分吗?OutputStreamInputStreamOutputStreamInputStream

谢谢


答案 1

似乎有很多链接和其他类似的东西,但没有使用管道的实际代码。使用java.io.PipedInputStreamjava.io.PipedOutputStream的优点是没有额外的内存消耗。 返回原始缓冲区的副本,这意味着无论内存中有什么,您现在都有它的两个副本。然后写入一个意味着您现在有三个数据副本。ByteArrayOutputStream.toByteArray()InputStream

代码使用(帽子提示从注释中@John Manko):lambdas

PipedInputStream in = new PipedInputStream();
final PipedOutputStream out = new PipedOutputStream(in);
// in a background thread, write the given output stream to the
// PipedOutputStream for consumption
((Runnable)() -> {originalByteArrayOutputStream.writeTo(out);}).run();

manko@John指出的一件事是,在某些情况下,当您无法控制 OutputStream 的创建时,您最终可能会遇到创建者可能会过早清理 OutputStream 对象的情况。如果你得到 ,那么你应该尝试反转构造函数:ClosedPipeException

PipedInputStream in = new PipedInputStream(out);
((Runnable)() -> {originalByteArrayOutputStream.writeTo(out);}).run();

请注意,您也可以反转以下示例的构造函数。

代码使用:try-with-resources

// take the copy of the stream and re-write it to an InputStream
PipedInputStream in = new PipedInputStream();
    new Thread(new Runnable() {
        public void run () {
            // try-with-resources here
            // putting the try block outside the Thread will cause the
            // PipedOutputStream resource to close before the Runnable finishes
            try (final PipedOutputStream out = new PipedOutputStream(in)) {
                // write the original OutputStream to the PipedOutputStream
                // note that in order for the below method to work, you need
                // to ensure that the data has finished writing to the
                // ByteArrayOutputStream
                originalByteArrayOutputStream.writeTo(out);
            }
            catch (IOException e) {
                // logging and exception handling should go here
            }
        }
    }).start();

我写的原始代码:

// take the copy of the stream and re-write it to an InputStream
PipedInputStream in = new PipedInputStream();
final PipedOutputStream out = new PipedOutputStream(in);
new Thread(new Runnable() {
    public void run () {
        try {
            // write the original OutputStream to the PipedOutputStream
            // note that in order for the below method to work, you need
            // to ensure that the data has finished writing to the
            // ByteArrayOutputStream
            originalByteArrayOutputStream.writeTo(out);
        }
        catch (IOException e) {
            // logging and exception handling should go here
        }
        finally {
            // close the PipedOutputStream here because we're done writing data
            // once this thread has completed its run
            if (out != null) {
                // close the PipedOutputStream cleanly
                out.close();
            }
        }   
    }
}).start();

此代码假定 是,因为它通常是唯一可用的输出流,除非您要写入文件。我希望这有帮助!这样做的好处是,由于它位于单独的线程中,因此它也并行工作,因此无论消耗输入流的任何内容也将从旧的输出流中流出。这是有益的,因为缓冲区可以保持较小,并且您将具有更少的延迟和更少的内存使用量。originalByteArrayOutputStream ByteArrayOutputStream

如果没有 ,则必须使用类中的一个方法或子类中可用的其他方法之一,而不是使用 。ByteArrayOutputStreamwriteTo()write()java.io.OutputStream


答案 2

An 是将数据写入其中的一个。如果某个模块公开了 一个,则期望在另一端有一些读数。OutputStreamOutputStream

另一方面,公开的东西指示您将需要侦听此流,并且将有您可以读取的数据。InputStream

因此,可以将InputStreamOutputStream

InputStream----read---> intermediateBytes[n] ----write----> OutputStream

正如有人所说,这就是IOUtils的方法可以让你做的事情。走另一条路是没有意义的...希望这是有道理的copy()

更新:

当然,我越是想到这一点,我就越能看到这实际上是一个要求。我知道一些评论提到了输入/输出流,但还有另一种可能性。Piped

如果公开的输出流是 ,则始终可以通过调用该方法来获取完整内容。然后,可以使用子类创建输入流包装器。这两个是伪流,它们基本上都只是包装一个字节数组。因此,以这种方式使用流在技术上是可行的,但对我来说,它仍然很奇怪......ByteArrayOutputStreamtoByteArray()ByteArrayInputStream


推荐