Question

Suppose I have a method that take in an InputStream.

This method need to wrap this InputStream with a BufferedInputStream to use its mark and reset functionality. However, the passed in InputStream might still be used by the caller of the method.

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();
    }
}

My questions is: what exactly happen to the original InputStream when the BufferedInputStream is read (or initialized)?

My assumption is that the original InputStream will also move forward if the BufferedInputStream is read. However, after debugging my code, I have found that the InputStream will return -1 instead when read.

If the original InputStream is not readable after such process, how should I go about achieving my purpose:

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()

EDIT: I suppose what I'm asking for is quite generic and therefore requires a lot of work. As for what I'm working on, I actually don't need the full mark & reset capability so I have found a small work around. However, I will leave the 2nd part of the question here, so feel free to attempt this problem :).

Was it helpful?

Solution

The default bufferSize of a BufferedInputStream is 8192, so when you're reading from BufferedInputStream, it tries to fill it's buffer. So, if you have to read from your InputStream less bytes, than the bufferSize, then the full content of your InputStream is read to the buffer, therefore you're getting -1 after reading from BufferedInputStream

Have a look at the BufferedInputStream source code: http://www.docjar.com/html/api/java/io/BufferedInputStream.java.html

OTHER TIPS

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

Looks like the BufferedInputStream uses the InputStream for the actions performed with the data stream. The Buffered class simply implements a buffer array for internal use.

Not sure what you could use instead, apart from perhaps copying the InputStream so that you have a second object to call.

BufferedInputStream will pre-load data from the underlying InputStream in batches, which will trigger respective move of the underlying InputStream position. If the buffer size is enough to consume all data from the underlying stream in one go you may well observe the behavior you describe.

Two things:

  1. Any API that accepts a stream as input parameter is probably going to use that stream, so it is unreasonable for the caller to expect the stream to remain in any kind of usable state. Perhaps it would have been better for the java stream classes to enforce single ownership somehow to make that clearer.

  2. As a special case, BufferedInputStream is going to use the underlying stream that it "wraps" because it achieves (a limited form of) mark and reset by buffering block reads, as others have pointed out.

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;
    }
}

then you can call the getBufferSize() after read() to see the difference between a small file and a larger file.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top