1

Here is my code:

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;

public class MarkAndResetDemo {

    public static void main(String[] args) {
        String s = "Today is Sunday!";
        byte buf[] = s.getBytes();
        
        System.out.println("s: "+s);
        ByteArrayInputStream in = new ByteArrayInputStream(buf);
        int c, count = 0;
        
        try(BufferedInputStream f = new BufferedInputStream(in, 4)) {//Line 1
            while((c=f.read()) != -1) {
                System.out.print((char)c);
                count++;
                
                if(count==3) f.mark(2); //Line 2
                
                if(count==8) f.reset(); //Line 3
                
            }
        }
        catch(IOException e) {
            e.printStackTrace();
        }

    }

}

When the count is set as 8 in Line 3, output is:

s: Today is Sunday!

Today isjava.io.IOException: Resetting to invalid mark

When the count is set as 7 in Line 3, output is:

s: Today is Sunday!

Today iay is Sunday!

So my question is why "invalid mark" exception is not appearing when count is 7 in Line 3 since more than 2 bytes have been read since the mark(int i) was last called? It seems that internal buffer of BufferedInputStream is being filled one byte at a time unless mark(int i) is invalidated.

I know that BufferedInputStream will read chunk of data of size equal to its internal buffer from the inputstream (and here the buffer size is 4). So after 4 iterations of while loop the internal buffer of BufferedInputStream should contain the next 4 bytes from the byte array(buf[] which means the characters 'y', ' ', 'i', 's' in byte encoded form). Also the mark(2) in Line 2 will place a hook on the current position(the next byte to be read in the inputstream) while mark(int i) is called.

Shri
  • 109
  • 9

2 Answers2

1

When the mark is set, the buffer contains 'Toda' and the marked character is 'a'. When we need to refill the buffer to print 'y', the first 3 characters are discarded (because they aren't needed for the mark), three new characters are read, and the buffer now contains 'ay i'. After printing 7 characters 'ay ' we haven't needed to refill the buffer, so reset can still reset to the 'a'.

If you want to understand things like this, put some breakpoints in the JDK classes.

tgdavies
  • 10,307
  • 4
  • 35
  • 40
0

Thanks, tgdavies for your explanation and your advice to use the breakpoints. I could see the protected fields of the BufferedInputStream like markpos, marlimit, pos and count. After playing with the above code by setting different values for marklimit and internal buffer size I came to these conclusions:

For internal buffer of length n >= marklimit:

If markpos = k where k is the index of the internal buffer(buf) and reset is not called even after (n-k) bytes have been read from the buf since mark() was last called then on reading the next input from the input stream:

Bytes from index position k to n-1 of buf are written at index position 0 to n-k-1 and at the index ranging from n-k to n-1 new data is written and the value of pos(the index position of the next byte to be read in buf) becomes n-k+1 since by now one byte from the newly added data has been read.

For internal buffer of length n < marklimit:

A new buffer of length marklimit will be created after n+k bytes have been read and (n+k+1)th byte is about to be read.

I know it is a long explanation but thought this might be useful for someone else if they come across this mark() and reset().

Shri
  • 109
  • 9