通过提供InputStream getter来延迟访问InputStream

时间:2012-08-12 21:19:59

标签: java io inputstream

我正在实现的API处理包含分层结构数据的InputStreams,即嵌套块,包括叶块中的许多图像。 (如果你必须知道,我正在解析的是CBEFF数据。)每个数据块都带有一个包含一些关于该块的元数据的标题。

1st level 1 header
    1st level 2 header
    1st level 2 data block
    2nd level 2 header
    2nd level 2 data block
2nd level 1 header
    3rd level 2 header
    3rd level 2 data block

原始的InputStream是我的API类的构造函数的参数,并在层次结构中传递。 目前我正在我的API类的构造函数中将图像读入字节数组,因此每个构造函数在读取该类负责的完整数据时会阻塞,稍后当客户端调用该API类的相关getter方法时,它们将获得从内存中提供的图像数据。我宁愿以某种懒惰的InputStream形式向我的API的客户端提供包含的图像,这样只有客户端读取由此产生的结果InputStream的字节,才能从原始的InputStream中读取图像字节。吸气。例如,这使得可以进行渐进式渲染,这在原始InputStream很慢时非常有用。

使用InputStreams有一种优雅的方法来解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

InputStream不适合随机访问。因此,在大多数情况下,阅读部分内容并不适用,即使您可以使用resetskip的组合对某些输入流实现类似的效果。但并非所有流都支持reset,跳过字节通常与读取字节一样昂贵。

所以我建议你尝试一些替代方法。您可以将整个流缓冲到某个随机访问缓冲区,就像临时文件一样,这仍然意味着首先从流中读取所有字节。或者您找到了一种随机访问原始源的方法。您没有指定您正在处理的来源,例如对于HTTP连接,您可以使用download parts range request。类似的解决方案可能适用于其他来源。

无论您如何实施随机访问(并看到您的评论,您可能会使用InputStream resetskip),您可以创建自己的类表示该流的一部分。您可以通过继承FilterInputStream来使该类本身成为InputStream的实例。

cLass SubStream extends FilterInputStream {
    private long offset;
    public SubStream(long offset, InputStream parent) {
        super(parent);
        this.offset = offset;
    }
    public SubStream(InputStream parent) {
        this(0, parent);
    }
    @Override public void reset() throws IOException {
        in.reset();
        in.skip(offset);
    }
    public SubStream subStream(long offset) {
        return new FilterInputStream(this.offset + offset, in);
    }
    public Object syncObject() {
        return in;
    }
}

您必须确保使用其中一个流的任何操作首先调用reset。如果您需要强制执行适当的流末尾处理,则必须覆盖大多数read实现。如果可能进行并发访问,那么您将需要同步基础流上的操作。所以使用这个类的代码看起来像这样:

     synchronized(part.syncObject()) {
         part.reset();
         return read(part);
     }