4

有许多 java 标准和 3rd 方库,在它们的公共 API 中,有写入或读取Stream. 一个例子是javax.imageio.ImageIO.write()OutputStream处理过的图像的内容写入其中。另一个例子是iText pdf 处理库,它将OutputStream生成的 pdf 写入其中。第三个示例是 AmazonS3 Java API,InputStream它将读取它并在S3 存储中创建文件。

当您想将其中两个结合起来时,就会出现问题。例如,我有一个图像BufferedImage,我必须使用它ImageIO.write来将结果推送到OutputStream. 但是没有直接的方法将它推送到 Amazon S3,因为 S3 需要InputStream.
解决这个问题的方法很少,但这个问题的主题是ByteArrayOutputStream.

背后的想法ByteArrayOutputStream是使用包装的中间字节数组,Input/Output Stream以便想要写入输出流的人将写入数组,而想要读取的人将读取数组。

我想知道为什么ByteArrayOutputStream不允许在不复制字节数组的情况下对其进行任何访问,例如,提供一个InputStream可以直接访问它的字节数组。访问它的唯一方法是调用toByteArray(),这将复制内部数组(标准数组)。这意味着,在我的图像示例中,我将在内存中保存三个图像副本:

  • 首先是实际的BufferedImage
  • 其次arrayOutputStreamand的内部
  • 第三个是由我制作的副本,toByteArray()所以我可以创建 InputStream.

这种设计如何合理?

  • 隐藏实现?只需提供getInputStream(),实现保持隐藏。
  • 多线程?ByteArrayOutputStream无论如何都不适合多线程访问,所以这是不可能的。

此外,ByteArrayOutputStreamApache 的commons-io库(具有不同的内部实现)提供了第二种风格的 . 但是两者都具有完全相同的公共接口,不提供不复制就访问字节数组的方法。

4

3 回答 3

6

我想知道为什么 ByteArrayOutputStream 不允许在不处理它的情况下对字节数组进行任何访问,例如,提供一个可以直接访问它的 InputStream。

我能想到四个原因:

  • 当前实现使用单字节数组,但它也可以实现为字节数组的链表,将最终数组的创建推迟到应用程序请求它。如果应用程序可以看到实际的字节缓冲区,则它必须是单个数组。

  • 与您的理解相反的ByteArrayOutputStream 线程安全的,并且适合在多线程应用程序中使用。但是,如果提供对字节数组的直接访问,则很难看到如何在不产生其他问题的情况下进行同步。

  • API 需要更复杂,因为应用程序还需要知道当前缓冲区高水位线在哪里,以及字节数组是否(仍然)是活动字节数组。(ByteArrayOutputStream实现有时需要重新分配字节数组......这将使应用程序持有对不再数组的数组的引用。)

  • 当您公开字节数组时,您允许应用程序修改数组的内容,这可能会出现问题。


这种设计如何合理?

该设计是为比您的更简单的用例量身定制的。Java SE 类库并不旨在支持所有可能的用例。但它们不会阻止您(或第 3 方库)为其他用例提供其他流类。


底线是 Sun 设计者决定不公开字节数组ByteArrayOutputStream,并且 (IMO) 你不太可能改变他们的想法。

(如果你想尝试,这不是正确的地方。

  • 尝试通过 Bugs 数据库提交 RFE。
  • 或者开发一个补丁来增加功能,并通过相关渠道提交给 OpenJDK 团队。如果你包含全面的单元测试和文档,你会增加你的机会。)

如果您能想出一个不太危险的 API 设计,您可能会更成功地说服 Apache Commons IO 开发人员相信您的论点是正确的。

或者,没有什么能阻止您只实现您自己的特殊用途版本,该版本公开其内部数据结构。该代码是 GPL 的,因此您可以复制它……遵守有关代码分发的正常 GPL 规则。

于 2011-06-13T00:29:45.757 回答
2

我认为您正在寻找的行为是Pipe。ByteArrayOutputStream 只是一个 OutputStream,而不是输入/输出流。它不是为您的想法而设计的。

于 2011-06-13T00:21:51.413 回答
2

幸运的是,内部数组是protected,因此您可以对其进行子类化,并将 a 包裹ByteArrayInputStream在它周围,而无需任何复制。

于 2011-06-13T00:29:53.777 回答