反转 InputStream/OutputStream(双向)操作

问题描述 投票:0回答:1

观察到很多库只支持一个方向的流处理,比如压缩、加密等

GZIPInputStream
/
GZIPOutputStream
假设你只会在阅读时膨胀(包装
InputStream
)和放气写(包装
OutputStream
).

同样,许多通过 BouncyCastle 的 PGP 示例仅执行读取时解密(再次,包装

InputStream
)和写入时加密(再次,包装
OutputStream

基于我在 SO 和其他地方遇到的混合示例,我正在尝试编写一组通用实用函数,这将允许(可能通过管道与

PipedInputStream
/
PipedOutputStream
) 支持双向流处理的能力,例如使用 GZIP:

  • 阅读时膨胀(支持开箱即用
  • 写入时放气(支持开箱即用
  • 写入时膨胀缺失;将压缩数据从套接字即时膨胀到磁盘的示例用例
  • 读取时放气缺失;将未压缩数据从磁盘即时放气到套接字的示例用例

对于通过

InputStream
处理运行
OutputStream
的情况(deflate on write),以下代码有效:

另见:

IOUtils

static InputStream outputTransformingInputStream(InputStream inputStream, Function<OutputStream, OutputStream> transformer) {
    try {
        var pipedInputStream = new PipedInputStream();
        var pipedOutputStream = new PipedOutputStream(pipedInputStream);
        var transformerThread = new Thread(() -> {
            try (var transformerOutputStream = transformer.apply(pipedOutputStream)) {
                IOUtils.copy(inputStream, transformerOutputStream);
                transformerOutputStream.flush();
            } 
            catch (IOException exception) {
                throw new RuntimeException(exception);
            }
        });
        transformerThread.start();
        return pipedInputStream;
    }
    catch (IOException exception) {
        throw new RuntimeException(exception);
    }
}

用于,例如:

// Deflating when reading from an InputStream
var inflatedInputStream = new FileInputStream("/path/to/file.txt");
var deflatingInputStream = outputTransformingInputStream(inflatedInputStream, GZIPOutputStream::new);
var deflatedBytes = deflatingInputStream.readAllBytes(); // Works 👍

逆向方法不起作用(导致空

byte[]
),也许这只是因为我盯着溪流和管道看的时间太长了,我的订单乱七八糟:

另见:

IOUtils

static OutputStream inputTransformingOutputStream(OutputStream outputStream, Function<InputStream, InputStream> transformer) {
    try {
        var pipedOutputStream = new PipedOutputStream();
        var pipedInputStream = new PipedInputStream(pipedOutputStream);
        var transformerThread = new Thread(() -> {
            try (var transformingInputStream = transformer.apply(pipedInputStream)) {
                IOUtils.copy(transformingInputStream, outputStream);
                outputStream.flush();
            }
            catch (IOException exception) {
                throw new RuntimeException(exception);
            }
        });
        transformerThread.start();
        return pipedOutputStream;
    }
    catch (IOException exception) {
        throw new RuntimeException(exception);
    }
}

这个示例调用导致空

inflatedBytes
.

// Inflating when writing to an OutputStream
var inflatedOutputStream = new ByteArrayOutputStream();
var inflatingOutputStream = StreamFactory.inputTransformingOutputStream(inflatedOutputStream, GZIPInputStream::new);
inflatingOutputStream.write(deflatedBytes); // deflatedBytes previously deflated, see above
inflatingOutputStream.flush();
var inflatedBytes = inflatedOutputStream.toByteArray(); // Empty 👎

所以,问题:

  • PipedInputStream
    /
    PipedOutputStream
    实用方法示例是泛化此功能的最佳方法吗?
  • 如果是这样,有人能告诉我我在
    inputTransformingOutputStream
    函数中哪里出错了吗?
  • 如果不是,那么创建对双向流处理的通用支持的更好方法是什么?
java inputstream outputstream
1个回答
2
投票

虽然我可以分享你的观察,但我看不出这里有什么问题。让我们看看两个缺失的例子:

  • 写入时膨胀(缺失;将压缩数据从套接字即时膨胀到磁盘的示例用例)
  • 读取时放气(缺失;将未压缩数据从磁盘即时放气到套接字的示例用例)

在这两种情况下,您都需要读取数据、处理(膨胀/收缩)并写入数据。 对于这三个步骤,将处理移动到左侧(读取和膨胀/收缩)还是右侧(膨胀/收缩和写入)几乎没有影响。出于同样的原因,它也是一个很小的影响,其中一个是左的,另一个是右的。

您绝对可以使用现有类构建您提到的用例。

© www.soinside.com 2019 - 2024. All rights reserved.