Input/Output Streams
Explore how to read data from and write data to files and other input/output streams.
Understanding Streams in Java: Input Streams and Output Streams
In Java, a stream represents a sequence of data flowing from a source to a destination. Think of it as a pipeline connecting data producers and consumers. Java's stream API provides a powerful and flexible way to handle input and output (I/O) operations. Streams can represent various data sources and destinations, such as files, network connections, memory buffers, and even keyboard input.
Two Main Types of Streams: Input Streams and Output Streams
Java distinguishes between two primary types of streams:
- Input Streams: Used for reading data from a source. They are the bridge to retrieve information from somewhere else.
- Output Streams: Used for writing data to a destination. They're the conduit to send information somewhere.
Input Streams (Reading Data)
An input stream is used to read data from a source. The source could be a file, network connection, in-memory array, or any other place where data resides. The most fundamental abstract class for input streams in Java is java.io.InputStream
.
java.io.InputStream
: The Abstract Base Class
InputStream
is an abstract class, meaning you cannot directly create an instance of it. Instead, you work with concrete subclasses that provide specific implementations for reading data from different sources. InputStream
defines the core methods for reading data.
Common Methods of InputStream
:
int read()
: Reads the next byte of data from the input stream. Returns the byte as an integer value between 0 and 255 (inclusive). If the end of the stream is reached, it returns -1. This is a blocking operation, meaning it will wait until data is available or the end of the stream is reached.int read(byte[] b)
: Reads up tob.length
bytes of data from the input stream into the byte arrayb
. Returns the number of bytes actually read. Returns -1 if the end of the stream is reached.int read(byte[] b, int off, int len)
: Reads up tolen
bytes of data from the input stream into the byte arrayb
, starting at offsetoff
. Returns the number of bytes actually read. Returns -1 if the end of the stream is reached.long skip(long n)
: Skips over and discardsn
bytes of data from the input stream. Returns the actual number of bytes skipped, which may be less thann
if the end of the stream is reached.int available()
: Returns an estimate of the number of bytes that can be read from the input stream without blocking. Note that this is only an *estimate* and might not be accurate.void close()
: Closes the input stream and releases any system resources associated with it. It's crucial to close streams when you're finished using them to prevent resource leaks.void mark(int readlimit)
: Marks the current position in the input stream. Subsequent calls toreset()
will reposition the stream to this marked position.readlimit
specifies the maximum number of bytes that can be read after the mark is set before the mark becomes invalid. Not allInputStream
subclasses support marking.void reset()
: Repositions the stream to the last marked position. Throws anIOException
if no mark has been set or if the mark has become invalid.boolean markSupported()
: Returnstrue
if this input stream supports themark()
andreset()
methods;false
otherwise.
Common InputStream
Subclasses:
FileInputStream
: Reads data from a file.ByteArrayInputStream
: Reads data from a byte array.ObjectInputStream
: Reads objects from a stream (used for deserialization).BufferedInputStream
: Provides buffering to improve the efficiency of reading data from an underlying input stream.DataInputStream
: Reads primitive data types (e.g., int, float, boolean) from an underlying input stream in a machine-independent way.
Example (Reading from a file):
import java.io.FileInputStream;
import java.io.IOException;
public class InputStreamExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("my_file.txt")) {
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data); // Cast to char to print as text
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Output Streams (Writing Data)
An output stream is used to write data to a destination. The destination could be a file, network connection, in-memory array, or any other place where data can be stored. The most fundamental abstract class for output streams in Java is java.io.OutputStream
.
java.io.OutputStream
: The Abstract Base Class
OutputStream
is an abstract class, meaning you cannot directly create an instance of it. Instead, you work with concrete subclasses that provide specific implementations for writing data to different destinations. OutputStream
defines the core methods for writing data.
Common Methods of OutputStream
:
void write(int b)
: Writes the specified byte (represented as an integer) to the output stream. Only the lowest 8 bits of the integer are written.void write(byte[] b)
: Writesb.length
bytes from the byte arrayb
to the output stream.void write(byte[] b, int off, int len)
: Writeslen
bytes from the byte arrayb
, starting at offsetoff
, to the output stream.void flush()
: Flushes the output stream, forcing any buffered output bytes to be written to the underlying destination. Some output streams buffer data for efficiency, andflush()
ensures that the data is immediately written.void close()
: Closes the output stream and releases any system resources associated with it. It's crucial to close streams when you're finished using them to prevent resource leaks and ensure that all data is written.
Common OutputStream
Subclasses:
FileOutputStream
: Writes data to a file.ByteArrayOutputStream
: Writes data to a byte array in memory.ObjectOutputStream
: Writes objects to a stream (used for serialization).BufferedOutputStream
: Provides buffering to improve the efficiency of writing data to an underlying output stream.DataOutputStream
: Writes primitive data types (e.g., int, float, boolean) to an underlying output stream in a machine-independent way.
Example (Writing to a file):
import java.io.FileOutputStream;
import java.io.IOException;
public class OutputStreamExample {
public static void main(String[] args) {
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
String message = "Hello, world!";
byte[] bytes = message.getBytes(); // Convert string to bytes
fos.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Important Notes:
- Always close streams in a
finally
block or using the try-with-resources statement (as shown in the examples) to ensure that resources are released, even if an exception occurs. - Buffering streams (
BufferedInputStream
andBufferedOutputStream
) can significantly improve performance, especially when dealing with small or frequent read/write operations. - When dealing with character data, consider using
Reader
andWriter
classes (character streams) instead ofInputStream
andOutputStream
(byte streams) for easier handling of character encodings.