Reputation:
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
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
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
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
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 thepos
field at the time the lastmark
method was called.This value is always in the range
-1
throughpos
. If there is no marked position in the input stream, this field is-1
. If there is a marked position in the input stream, thenbuf[markpos]
is the first byte to be supplied as input after areset
operation. Ifmarkpos
is not-1
, then all bytes from positionsbuf[markpos]
throughbuf[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 ofcount
,pos
, andmarkpos
); they may not be discarded unless and until the difference betweenpos
andmarkpos
exceedsmarklimit
.
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