1

我可以看到有很多关于重用的帖子InputStream。我理解InputStream是一次性的,不能重复使用。

但是,我有一个这样的用例:

我已经DropBox通过DropBoxInputStream使用DropBox's Java SDK. 然后我需要通过传递文件将文件上传到另一个系统InputStream。但是,作为下载的一部分,我必须提供MD5文件的。所以我必须在上传文件之前从流中读取文件。因为DropBoxInputStream我收到的只能使用一次,所以我必须DropBoxInputStream在计算好MD5之后再上传文件。程序是这样的:

  1. 获取第一个 DropBoxInputStream
  2. 从 DropBoxInputStream 读取并计算 MD5
  3. 获取第二个 DropBoxInputStream
  4. 使用 MD5 和第二个 DropBoxInputStream 上传文件。

我在想,如果在InputStream计算之前有很多方法可以让我“缓存”或“备份”,MD5这样我就可以保存再次获得相同结果的第 3 步DropBoxInputStream

非常感谢

编辑:

对不起,我错过了一些信息。

我目前正在做的是使用 aMD5DigestOutputStream来计算MD5. 我通过流式传输数据 MD5DigestOutputStream并将它们本地保存为临时文件。一旦数据通过MD5DigestOutputStream,它将计算MD5

然后我调用第三方库使用计算出的 md5 和FileInputStream从临时文件中读取的 a 来上传文件。

但是,有时这需要巨大的磁盘空间,我想消除使用临时文件的需要。我使用的库只接受一个MD5and InputStream。这意味着我必须自己计算MD5。我的计划是使用 myMD5DigestOutputStream将数据写入/dev/null(不保留文件),以便我可以计算MD5,并InputStream再次从 DropBox 获取并将其传递给我使用的库。我假设库将能够直接从中获取文件,DropBox而无需我将文件缓存在磁盘的内存中。它会起作用吗?

4

2 回答 2

3

输入流并不是真正为创建副本或重用而设计的,它们专门用于您不想读入字节数组并对其使用数组操作的情况(当整个数组被'不可用,例如套接字通信)。您可以缓冲到字节数组中,这是将流中的部分读取到字节数组缓冲区中的过程,直到您有足够的信息。

但这对于计算 md5 是不必要的。注意InputStream是抽象的,所以它需要在扩展类中实现。它有许多实现GZIPInputStream——文件输入流等。在设计模式中,这些是IO 流的装饰器:它们为抽象基 IO 类添加了额外的功能。例如,GZIPInputStream对流进行 gzip 压缩。

因此,您需要一个流来为 md5 执行此操作。令人高兴的是,有一个有据可查的类似事情:请参阅答案。所以你应该能够传递你的 Dropbox 输入流(因为它本身就是一个输入流)来创建一个新DigestInputStream的 ,然后你就可以使用 md5 并像以前一样继续阅读。

担心类型转换?Java 中装饰器的想法是,由于InputStream 基类接口所有方法和执行 IO 所需的“牛肉”,因此在每个流实现的构造函数中传递继承自的对象实例并没有什么害处InputStream,而且您仍然可以做同样的核心 IO。

最后,我可能应该回答您的实际问题 - 说您仍然想“缓存”或“备份”流?好吧,您可以将其写入字节数组。这是有据可查的,但是当您的流变得更加复杂时,这可能会变得很糟糕。或者,尝试查看PushbackInputStream. 在这里,您可以轻松编写一个函数来读取 n 个字节,对它们执行和操作,然后将它们恢复到流中。在 Java 中避免这些流的实现通常很好,因为它不利于内存使用,但并不比缓冲所有你必须做的事情更糟糕。

或者,当然,我会选择DigestInputStream.

希望这可以帮助,

最好的。

于 2013-05-23T09:14:45.160 回答
1

您不需要从 DropBox 打开新的 InputStream。

从 DropBox 读取文件后,您就可以在本地获得它。所以它要么在内存中(在字节数组中),要么你将它存储在本地文件中。现在您可以创建一个 InputStream,它从内存 (ByteArrayInputStream) 或磁盘 (FileInputStream) 读取数据以上传文件。

因此,不是缓存 InputStream(你不能),而是缓存内容(你可以)。

于 2013-05-23T08:39:56.713 回答