How to Reset and Reuse InputStream
In Java, InputStream is commonly used to read data from files, network sockets, or in-memory buffers. A frequent requirement is to read the same stream multiple times. However, most input streams are forward-only and do not support rewinding by default. Let us delve into understanding how to use Java InputStream’s reset method when reading a file.
1. Understanding the InputStream Class
The InputStream class in Java is an abstract superclass designed for reading byte-oriented input streams. It serves as the foundation for all classes that represent an input stream of bytes, such as reading data from files, network connections, or byte arrays. Key characteristics of the InputStream class include:
- Sequential Data Access: Data is read in a forward-only, sequential manner, from the beginning of the stream towards the end. Random access or jumping backward is not inherently supported.
- Mark and Reset Support: The class provides
mark(int readlimit)andreset()methods that allow a program to mark a position in the stream and return to it later. However, support for these operations depends on the specific subclass implementation and is not guaranteed. - Reset Operation Caution: Because not all streams support the
reset()method, it is important to verify support before attempting to reset the stream to a previously marked position. Attempting to callreset()on an unsupported stream can lead to anIOException.
Before using the reset() method, always check if the stream supports marking and resetting by calling:
if (inputStream.markSupported()) {
// Safe to use mark() and reset()
} else {
// Mark/reset not supported, consider alternative logic
}
Understanding these characteristics is essential when working with InputStream to ensure robust and error-free input handling, especially when processing data streams that require lookahead or re-reading of bytes.
2. Code Example
In Java, InputStream is commonly used to read data from files, network sockets, or in-memory buffers. A frequent requirement is to read the same stream multiple times. However, most input streams are forward-only and do not support rewinding by default. Let us take a look at the code to understand how to use Java InputStream’s reset method when reading a file.
import java.io.*;
public class InputStreamResetDemo {
public static void main(String[] args) throws Exception {
// -------------------------------------------------
// 1. ByteArrayInputStream (in-memory reset)
// -------------------------------------------------
byte[] data = "ABC".getBytes();
ByteArrayInputStream byteArrayStream =
new ByteArrayInputStream(data);
System.out.println("ByteArrayInputStream:");
readOnce(byteArrayStream);
byteArrayStream.reset(); // always supported
readOnce(byteArrayStream);
// -------------------------------------------------
// 2. BufferedInputStream (mark/reset)
// -------------------------------------------------
System.out.println("\nBufferedInputStream:");
try (BufferedInputStream bufferedStream =
new BufferedInputStream(
new FileInputStream("sample.txt"))) {
if (bufferedStream.markSupported()) {
bufferedStream.mark(1024);
}
readOnce(bufferedStream);
bufferedStream.reset(); // valid within mark limit
readOnce(bufferedStream);
}
// -------------------------------------------------
// 3. RandomAccessFile (true file repositioning)
// -------------------------------------------------
System.out.println("\nRandomAccessFile:");
try (RandomAccessFile raf =
new RandomAccessFile("sample.txt", "r")) {
readOnce(raf);
raf.seek(0); // move pointer back to start
readOnce(raf);
}
}
private static void readOnce(InputStream is) throws IOException {
int b;
while ((b = is.read()) != -1) {
System.out.print((char) b);
}
System.out.println();
}
private static void readOnce(RandomAccessFile raf) throws IOException {
int b;
while ((b = raf.read()) != -1) {
System.out.print((char) b);
}
System.out.println();
}
}
2.1 Code Explanation
This example demonstrates three different techniques for rereading data in Java. First, a ByteArrayInputStream is created from an in-memory byte array containing the string "ABC". Since all data is already loaded into memory, calling reset() reliably moves the read position back to the beginning, allowing the stream to be read twice without any additional configuration. Next, a BufferedInputStream wraps a FileInputStream to enable buffering and support for mark() and reset(). Before reading, the code checks markSupported() and marks the current position with a limit of 1024 bytes; as long as the number of bytes read does not exceed this limit, reset() correctly rewinds the stream to the marked position so the file content can be read again. Finally, the example uses RandomAccessFile, which does not rely on buffering or marking but instead provides true random access to the file; after reading the file once, the call to seek(0) explicitly moves the file pointer back to the start, enabling a second read. The helper readOnce methods simply iterate through each byte until end-of-stream and print the characters, making it easy to observe how each approach successfully rereads the same data using different underlying mechanisms.
2.2 Code Output
When this program runs, it executes the three stream examples sequentially and prints both a label and the data read from each source.
- In the first section, the program prints
ByteArrayInputStream:and then reads the in-memory byte array containingABC, printingABCto the console. After callingreset(), the internal cursor of the stream moves back to the beginning, so the same data is read and printed again, resulting in two identical lines. - In the second section, the program prints
BufferedInputStream:and reads the contents ofsample.txt. Assuming the file containsABC, the first read printsABC; after a successfulreset()within the mark limit, the stream rewinds to the marked position and printsABCagain. - In the final section, the program prints
RandomAccessFile:and reads the file once, outputtingABC. The call toseek(0)then moves the file pointer back to the start, allowing the file to be read again and printed a second time.
ByteArrayInputStream: ABC ABC BufferedInputStream: ABC ABC RandomAccessFile: ABC ABC
2.3 When Mark Position Gets Invalidated
When using the mark() and reset() methods with an InputStream, it’s important to understand that the mark position can become invalidated. This happens when the number of bytes read after the mark exceeds the read limit specified in the mark(int readlimit) call.
Once the read limit is surpassed, calling reset() may throw an IOException or fail to rewind the stream to the marked position. This behavior is because the underlying stream implementation might discard the buffered data beyond the read limit to save memory.
Therefore, when marking a position, choose a read limit large enough to cover the number of bytes you expect to read before resetting. Also, always check if the stream supports marking by using markSupported() before relying on these methods.
In practice, failing to respect the read limit can lead to subtle bugs where the stream cannot be reset as expected, causing data loss or requiring reopening of the stream.
3. Conclusion
Resetting an InputStream depends heavily on the concrete implementation. ByteArrayInputStream is the safest choice for in-memory data, while BufferedInputStream works well within mark limits. For true file rereading and random access, RandomAccessFile provides the most reliable solution. Choosing the right approach ensures correctness, performance, and maintainability.

