Java’s I/O is Built upon Streams
- Java programs perform I/O through streams.
- A stream is an abstraction that either produces or consumes information.
- A stream is linked to a physical device by the Java I/O system.
- This means that an input stream can abstract many kinds of input: from a disk file, a keyboard, or a network socket.
- Likewise, an output stream may refer to the console, a disk file, or a network connection.
- Java implements streams within class hierarchies defined in the java.io package.
Byte Streams and Character Streams
- Java defines two types of streams: byte and character.
- Byte streams provide a convenient means for handling input and output of bytes.
- Byte streams are used, for example, when reading or writing binary data.
- Character streams provide a convenient means for handling input and output of characters.
- They use Unicode and, therefore, can be internationalized.
- Also, in some cases, character streams are more efficient than byte streams.
The Byte Stream Classes
- Byte streams are defined by using two class hierarchies.
- At the top are two abstract classes: InputStream and OutputStream.
- Each of these abstract classes has several concrete subclasses that handle the differences among various devices, such as disk files, network connections, and even memory buffers.
- The byte stream classes in java.io are shown in the next table.
- The abstract classes InputStream and OutputStream define several key methods that the other stream classes implement.
- Two of the most important are read( ) and write( ), which, respectively, read and write bytes of data.
- Each has a form that is abstract and must be overridden by derived stream classes.

The Character Stream Classes
- Character streams are defined by using two class hierarchies.
- At the top are two abstract classes: Reader and Writer.

The Predefined Streams
- All Java programs automatically import the java.lang package.
- This package defines a class called System, which encapsulates several aspects of the run-time environment.
- System also contains three predefined stream variables: in, out, and err.
- These fields are declared as public, static, and final within System.
- This means that they can be used by any other part of your program and without reference to a specific System object.
Using the Byte Streams
Let’s explore FileInputStream and FileOutputStream by examining an example program named ByteStreamExample, which uses byte streams to copy test.txt, one byte at a time to another output file.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamExample {
public static void main(String[] args) throws IOException {
// this example will copy file contents
FileInputStream in = new FileInputStream("test.txt");
FileOutputStream out = new FileOutputStream("outtest.txt");
int read = 0;
while ((read = in.read()) != -1) {
out.write(read);
}
}
}
ByteStreamExample spends most of its time in a simple loop that reads the input stream and writes the output stream, one byte at a time.
Automatically Closing a File
- JDK 7 added a new feature that offers another way to manage resources, such as file streams, by automating the closing process.
- This feature, sometimes referred to as automatic resource management, or ARM for short, is based on an expanded version of the try statement.
- The principal advantage of automatic resource management is that it prevents situations in which a file (or other resource) is inadvertently not released after it is no longer needed.
Below is the updated ByteStreamExample using the try-with-resources.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamExample {
public static void main(String[] args) {
// this example will copy file contents
try (FileInputStream in = new FileInputStream("test.txt");
FileOutputStream out = new FileOutputStream("outtest.txt");) {
int read = 0;
while ((read = in.read()) != -1) {
out.write(read);
}
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}
Using the Character Streams
The following Java program reads data from a particular file using FileReader and writes it to another, using FileWriter.
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CharacterStreamExample {
public static void main(String[] args) {
// this example will copy file contents
try (FileReader in = new FileReader("test.txt");
FileWriter out = new FileWriter("outtest.txt");) {
int read = 0;
while ((read = in.read()) != -1) {
out.write(read);
}
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
}