避免多次获取相同的InputStream

时间:2013-05-23 07:49:57

标签: java stream dropbox

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

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

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

  1. 获取第一个DropBoxInputStream
  2. 从DropBoxInputStream中读取并计算MD5
  3. 获取第二个DropBoxInputStream
  4. 使用MD5和第二个DropBoxInputStream上传文件。
  5. 我在想,如果我在计算InputStream之前有很多方法可以“缓存”或“备份”MD5,以便我可以保存获取相同{的第3步{ {1}}再次?

    非常感谢

    编辑:

    抱歉,我错过了一些信息。

    我目前正在做的是我使用DropBoxInputStream来计算MD5DigestOutputStream。我在MD5上传输数据并将其作为临时文件保存在本地。数据通过MD5DigestOutputStream后,将计算MD5DigestOutputStream

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

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

2 个答案:

答案 0 :(得分:3)

输入流并非真正用于创建副本或重新使用,它们专门用于您不想读入字节数组并对其使用数组操作的情况(这在以下情况下特别有用)整个数组不可用,例如,用于例如套接字通信)。你可以缓冲到一个字节数组,这是从流中读取段到字节数组缓冲区的过程,直到你有足够的信息。

但是这对于计算md5是不必要的。请注意InputStream是抽象的,因此需要在扩展类中实现。它有许多实现 - GZIPInputStream,fileinputstream等。在设计模式中,这些是IO流的decorators:它们为抽象基类IO类添加了额外的功能。例如,GZIPInputStream gzips流。

所以,你需要的是为md5执行此操作的流。幸运的是,有一个记录良好的类似事情:见this回答。所以你应该能够传递你的Dropbox输入流(因为它本身就是一个输入流)来创建一个新的DigestInputStream,然后你可以像以前一样拿md5继续阅读。

担心打字? Java中装饰器的想法是,因为InputStream 基类接口所有方法和'牛'你需要做IO,所以传递继承自的对象的实例没有坏处InputStream在每个流实现的构造函数中,您仍然可以执行相同的核心IO。

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

或者,当然,我会选择DigestInputStream

希望这有帮助,

最佳。

答案 1 :(得分:1)

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

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

所以不是缓存InputStream(你可以“),而是缓存内容(你可以)。