Mark and reset Stream in Java
It is often useful to be able to read a few bytes, and then back up and reread them. For example, in a Java compiler you do not know for sure whether you are reading the token
<
<<, or
<<= until you have read one too many characters. It would be useful to be able to back up and reread the token once you know which token you have read.
Compiler design and other parsing problems provide many more examples, but this need occurs elsewhere as well.
Some, but not all, input streams allow you to mark a particular position in the stream and then return to it.
The
mark() , reset(), and markSupported()
methods in the
java.io.InputStream class determine this.
There can be only one mark in the stream at any given time. Marking a second location erases the first mark. If marking is not supported, the
mark()
and
reset()
methods throw IOExceptions.
The only two input stream classes in
java.io that always support marking are
- BufferedInputStream and
- ByteArrayInputStream.
The following program named
InMemoryStreams contains the basic pattern to follow when working with the ByteArrayInputStream.
package com.java.bytestreams;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class InMemoryStreams {
public static void main(String[] args) throws IOException {
String str1 = "Let us learn about In-memory Streams";
byte[] bytes = str1.getBytes();
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
// initialize variable to hold the return value
byte[] buffer = new byte[3];
int number=0;
int count = 0;
while((number = in.read(buffer)) != -1) {
for(byte b: buffer) {
System.out.println(b);
}
if (count ==2)
in.reset();
count++;
}
in.close();
}
}
However, other input streams like DataInputStream support marking when they are chained to a buffered input stream first.
BufferedInputStream Details
The buffer and the current state of the buffer are stored in protected fields.
The buffer itself is a byte array called buf
; the number of bytes in the buffer is an int
named count;
the index of the next byte that will be returned by read()
is an int called pos; the mark, if any, is an int called markpos
;
the read-ahead limit before the mark is invalidated is an int
called marklimit
.
Subclasses of BufferedInputStream can directly access all these fields, which can be important for performance.
protected byte[] buf
protected int count
protected int pos
protected int markpos
protected int marklimit
BufferedInputStream only overrides methods from InputStream and does not declare any new methods of its own. Marking and resetting are supported.
public synchronized int read() throws IOException
public synchronized int read(byte[] data, int offset, int length)
throws IOException
public synchronized long skip(long n) throws IOException
public synchronized int available() throws IOException
public synchronized void mark(int readLimit)
public synchronized void reset() throws IOException
public boolean markSupported()
In Java 2 and later, the two multibyte read()
methods try to fill the specified array or subarray completely by reading repeatedly from the underlying input stream. They return only when the requested number of bytes have been read, the end of stream is reached, or the underlying stream would block. This is not the case for most input streams (including buffered input streams in Java 1.1.x and earlier), which only attempt one read from the underlying stream or data source before returning.
Java I/O