user1462183
user1462183

Reputation:

Java: Inputstream mark limit

According to Java documentation, the readlimit parameter of the mark method in the Class InputStream server for set "the maximum limit of bytes that can be read before the mark position becomes invalid.". I have a file named sample.txt whose content is "hello". And i wrote this code:

import java.io.*;
public class InputStream{
 public static void main (String[] args) throws IOException {
  InputStream reader = new FileInputStream("sample.txt");
  BufferedInputStream bis = new BufferedInputStream(reader);
  bis.mark(1);
  bis.read();
  bis.read();
  bis.read();
  bis.read();
  bis.reset();
  System.out.println((char)bis.read());
 }
}

The output is "h". But if i after the mark method read more than one bytes, shouldn't i get an error for the invalid reset method call?

Upvotes: 8

Views: 7604

Answers (4)

parsifal
parsifal

Reputation: 592

I would put this down to documentation error.

The non-parameter doc for BufferedInputStream is "See the general contract of the mark method of InputStream," which to me indicates that BufferedInputStream does not behave differently, parameter doc notwithstanding.

And the general contract, as specified by InputStream, is

The readlimit arguments tells this input stream to allow that many bytes to be read before the mark position gets invalidated [...] the stream is not required to remember any data at all if more than readlimit bytes are read from the stream

In other words, readlimit is a suggestion; the stream is free to under-promise and over-deliver.

Upvotes: 5

DNA
DNA

Reputation: 42597

If you look at the source, particularly the fill() method, you can see (after a while!) that it only invalidates the mark when it absolutely has to, i.e. it is more tolerant than the documentation might suggest.

...
else if (pos >= buffer.length)  /* no room left in buffer */
   if (markpos > 0) {  /* can throw away early part of the buffer */
     int sz = pos - markpos;
     System.arraycopy(buffer, markpos, buffer, 0, sz);
     pos = sz;
     markpos = 0;
   } else if (buffer.length >= marklimit) {
     markpos = -1;   /* buffer got too big, invalidate mark */
     pos = 0;        /* drop buffer contents */
     ....

The default buffer size is relatively large (8K), so invalidation won't be triggered in your example.

Upvotes: 3

Philippe Marschall
Philippe Marschall

Reputation: 4604

This looks like a subtle bug. If you reduce the buffer sizey you'll get an IOException

public static void main(String[] args) throws IOException {
    InputStream reader = new ByteArrayInputStream(new byte[]{1, 2, 3, 4, 5, 6, 7, 8});
    BufferedInputStream bis = new BufferedInputStream(reader, 3);
    bis.mark(1);
    bis.read();
    bis.read();
    bis.read();
    bis.read();
    bis.reset();
    System.out.println((char)bis.read());
}

Upvotes: 1

Duncan Jones
Duncan Jones

Reputation: 69339

Looking at the implementation of BufferedInputStream, it describes the significance of the marker position in the JavaDocs (of the protected markpos field):

[markpos is] the value of the pos field at the time the last mark method was called.

This value is always in the range -1 through pos. If there is no marked position in the input stream, this field is -1. If there is a marked position in the input stream, then buf[markpos] is the first byte to be supplied as input after a reset operation. If markpos is not -1, then all bytes from positions buf[markpos] through buf[pos-1] must remain in the buffer array (though they may be moved to another place in the buffer array, with suitable adjustments to the values of count, pos, and markpos); they may not be discarded unless and until the difference between pos and markpos exceeds marklimit.

Hope this helps. Take a peek at the definitions of read, reset and the private method fill in the class to see how it all ties together.

In short, only when the class retrieves more data to fill its buffer will the mark position be taken into account. It will be correctly invalidated if more bytes are read than the call to mark allowed. As a result, calls to read will not necessarily trigger the behaviour advertised in the public JavaDoc comments.

Upvotes: 1

Related Questions