使用 BufferedInputStream 包装后对原始 InputStream 的影响

Posted

技术标签:

【中文标题】使用 BufferedInputStream 包装后对原始 InputStream 的影响【英文标题】:Effect on the original InputStream after wrapping with BufferedInputStream 【发布时间】:2014-02-12 07:52:16 【问题描述】:

假设我有一个接收 InputStream 的方法。

此方法需要用 BufferedInputStream 包装此 InputStream 以使用其标记和重置功能。但是,传入的 InputStream 可能仍会被方法的调用者使用。

public static void foo(InputStream is) throws Exception 
    BufferedInputStream bis = new BufferedInputStream(is);
    int b = bis.read();


public static void main(String[] args) 


    try 
        InputStream is = new FileInputStream(someFile);
        foo(is);
        int b = is.read(); // return -1
    catch (Exception e) 
        e.printStackTrace();
    

我的问题是:当 BufferedInputStream 被读取(或初始化)时,原始 InputStream 到底发生了什么?

我的假设是,如果 BufferedInputStream 被读取,原始 InputStream 也会向前移动。但是,在调试我的代码后,我发现 InputStream 在读取时会返回 -1。

如果在这样的过程之后原始的 InputStream 不可读,我应该如何实现我的目的:

InputStream is;
foo(is);               // Method only take in generic InputStream object
                       // Processing of the passed in InputStream object require mark and reset functionality
int b = is.read();     // Return the next byte after the last byte that is read by foo()

编辑: 我想我所要求的内容很笼统,因此需要做很多工作。至于我正在做的事情,我实际上不需要完整的标记和重置功能,所以我找到了一个小工作。但是,我将把问题的第二部分留在这里,所以请随意尝试这个问题:)。

【问题讨论】:

【参考方案1】:

http://docs.oracle.com/javase/7/docs/api/java/io/BufferedInputStream.html#BufferedInputStream%28java.io.InputStream%29

看起来 BufferedInputStream 使用 InputStream 来执行对数据流的操作。 Buffered 类只是实现了一个内部使用的缓冲区数组。

不知道你可以用什么代替,除了可能复制 InputStream 以便你有第二个对象可以调用。

【讨论】:

【参考方案2】:

BufferedInputStream 的默认 bufferSize 为 8192,因此当您从 BufferedInputStream 读取数据时,它会尝试填充其缓冲区。因此,如果您必须从InputStream 读取的字节数少于bufferSize,那么您的InputStream 的全部内容将被读取到缓冲区,因此在从BufferedInputStream

看看BufferedInputStream源代码:http://www.docjar.com/html/api/java/io/BufferedInputStream.java.html

【讨论】:

【参考方案3】:

BufferedInputStream 将分批预加载底层InputStream 的数据,这将触发底层InputStream 仓位的相应移动。如果缓冲区大小足以一次性消耗底层流中的所有数据,您可能会很好地观察到您描述的行为。

【讨论】:

【参考方案4】:

两件事:

    任何接受流作为输入参数的 API 都可能会使用该流,因此调用者期望流保持任何可用状态是不合理的。也许 java 流类以某种方式强制执行单一所有权以使这一点更清楚会更好。

    作为一种特殊情况,BufferedInputStream 将使用它“包装”的底层流,因为正如其他人所指出的那样,它通过缓冲块读取来实现(一种有限形式的)标记和重置。

【讨论】:

【参考方案5】:
private static class MybufferedInputStream extends BufferedInputStream 
    public MybufferedInputStream(InputStream in) 
        super(in);
    

    public int getBufferSize()
        int i=0;
        for (Byte byte1 : super.buf) 
            if (byte1!=0) 
                i++;
            
        
        return i;
    

那么你可以在read()之后调用getBufferSize()来查看小文件和大文件的区别。

【讨论】:

以上是关于使用 BufferedInputStream 包装后对原始 InputStream 的影响的主要内容,如果未能解决你的问题,请参考以下文章

缓冲输入输出流[也叫包装流] BufferedInputStream,BufferedOutputStream,BufferedReader和BufferedWriter

J05-Java IO流总结五 《 BufferedInputStream和BufferedOutputStream 》

bufferedinputstream的使用

深入研究BufferedInputStream内幕

BufferedInputStream 中的读取方法

FileInputstream --BufferedInputStream字节流读取使用方法