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() in the java.io.InputStream class determine this.
InputStream for Marking and Resetting Methods
public synchronized void mark(int readLimit)
public synchronized void reset()throws IOException
public boolean markSupported()
The boolean markSupported() method returns true if this stream supports marking and false if it does not.
Assuming the stream does support marking, the mark() method places a bookmark at the current position in the stream.
You can rewind the stream to this position later with reset() as long as you have not read more than readLimit bytes.
Marking and Resetting
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, and this need occurs in other domains as well.
Some (but not all) input streams allow you to mark a particular position in the stream and then return to it.
Three methods in the java.io.InputStream class handle marking and resetting:
public synchronized void mark(int readLimit)
public synchronized void reset() throws IOException
public boolean markSupported()
mark(readLimit): set bookmark at current position
reset(): return to bookmark (throws if unsupported/invalid)
Only one active mark; new mark() discards the previous one
After reading > readLimit bytes, the mark may be invalidated
Use BufferedInputStream to add mark/reset support to streams that lack it
Reading more than readLimit bytes after mark() may invalidate the mark.
reset() returns the stream to the bookmark if still valid.
The boolean markSupported() method returns true if this stream supports marking and false if it does not.
If marking is not supported, reset() throws an IOException and mark() does nothing. Assuming the stream does support marking,
the mark() method places a bookmark at the current position in the stream. You can rewind the stream to this position
later with reset() as long as you haven't read more than readLimit bytes.
There can be only one mark in the stream at any given time. Marking a second location erases the first mark.
The only two input stream classes in java.io that always support marking are BufferedInputStream (of which System.in is an instance) and
ByteArrayInputStream. However, other input streams, like DataInputStream , may support marking if they're chained to a buffered input stream first.
Scanner Examples
The addition of Scanner to Java makes what was formerly a tedious task into an easy one.
To understand why, let uslook at some examples. The following program averages a list of numbers entered at the keyboard:
// Use Scanner to compute an average of the values.
import java.util.*;
class AvgNums {
public static void main(String args[]) {
Scanner conin = new Scanner(System.in);
int count = 0;
double sum = 0.0;
System.out.println("Enter numbers to average.");
// Read and sum numbers.
while(conin.hasNext()) {
if(conin.hasNextDouble()) {
sum += conin.nextDouble();
count++;
}
else {
String str = conin.next();
if(str.equals("done"))
break;
else {
System.out.println("Data format error.");
return;
}
}
}
System.out.println("Average is " + sum / count);
}
}
The program reads numbers from the keyboard, summing them in the process, until the
user enters the string "done". It then stops input and displays the average of the numbers.
Here is a sample run:
Enter numbers to average.
1.2
2
3.4
4
done
Average is 2.65
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.