我可以看到有很多关于重用InputStream
的帖子。我理解InputStream
是一次性的事情,无法重复使用。
但是,我有一个这样的用例:
我已使用DropBox
获取DropBoxInputStream
,从DropBox's Java SDK
下载了该文件。然后,我需要通过传递InputStream
将文件上传到另一个系统。但是,作为下载的一部分,我必须提供该文件的MD5
。所以我必须在上传文件之前从流中读取文件。因为我收到的DropBoxInputStream
只能使用一次,所以在我计算DropBoxInputStream
之后和上传文件之前,我必须得到另一个MD5
。程序如下:
我在想,如果我在计算InputStream
之前有很多方法可以“缓存”或“备份”MD5
,以便我可以保存获取相同{的第3步{ {1}}再次?
非常感谢
编辑:
抱歉,我错过了一些信息。
我目前正在做的是我使用DropBoxInputStream
来计算MD5DigestOutputStream
。我在MD5
上传输数据并将其作为临时文件保存在本地。数据通过MD5DigestOutputStream
后,将计算MD5DigestOutputStream
。
然后我调用第三方库使用计算出的md5和从临时文件中读取的MD5
上传文件。
但是,这有时需要巨大的磁盘空间,我想删除使用临时文件的需求。我使用的图书馆只接受FileInputStream
和MD5
。这意味着我必须在我的头上计算InputStream
。我的计划是使用我的MD5
将数据写入MD5DigestOutputStream
(不保留文件),以便我可以计算/dev/null
,并再次从DropBox获取MD5
把它传递给我使用的库。我假设库将能够直接从InputStream
获取文件,而无需将文件缓存在磁盘的内存中。它会起作用吗?
答案 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(你可以“),而是缓存内容(你可以)。