Java I/O is centered on the concept of an I/O device, which is often a physical input or output device such as a keyboard, monitor, printer, or disk drive. Although you rarely interact with a device directly, I/O devices are always implicitly associated with I/O operations. The power of Java I/O lies in the fact that you use very similar classes and methods to read and write data regardless of the
specific I/O devices. This I/O abstraction is similar to the
graphics context[1] abstraction you learned about earlier in the course.
- Logical I/O devices
In addition to physical I/O devices, Java also supports logical I/O devices such as a block of memory or a string. Logical devices allow you to read data from strings or write data to memory, for example, as if they are physical devices. This
capability helps to unify the manner in which data is stored and retrieved and ultimately makes your job easier as a programmer.
To help underscore this point, consider the example of developing a cache program that stores commonly accessed Web information onto a hard disk. The same I/O operations used to store the information in memory could also be used to write the information to the hard disk.
Likewise, reading stored information from the hard disk would be very similar to reading it from memory.
In Java 1.1, an I/O device serves as an abstraction for input and output operations within the Java Input/Output (I/O) API, primarily using the `java.io` package. The purpose of an I/O device in this context is to facilitate reading data from input sources (e.g., files, keyboard, network sockets) and writing data to output destinations (e.g., files, console, network).
Functions of an I/O Device in Java 1.1 I/O API
-
Abstraction of Data Streams:
- Java 1.1 introduced an enhanced I/O model based on streams, which provide a unified way to handle different kinds of I/O devices.
- The
InputStream and OutputStream classes for byte-based data.
- The
Reader and Writer classes for character-based data (introduced in Java 1.1 to support Unicode).
-
Handling File Input and Output:
FileInputStream and FileOutputStream for reading and writing files in byte format.
FileReader and FileWriter for reading and writing files in character format.
-
Interfacing with the Console (Standard I/O):
System.in (for reading input from the keyboard).
System.out (for printing output to the console).
System.err (for error messages).
-
Buffered I/O for Performance Optimization:
BufferedInputStream and BufferedOutputStream for improving efficiency when reading/writing large amounts of data.
BufferedReader and BufferedWriter for character-based buffered I/O.
-
Support for Object Serialization (New in Java 1.1):
- Java 1.1 introduced object serialization with
ObjectInputStream and ObjectOutputStream, allowing objects to be converted into a byte stream and stored or transferred.
-
Interfacing with Network Streams:
Socket.getInputStream() and Socket.getOutputStream() allow network communication over TCP/IP.
-
Filter Streams for Data Processing:
FilterInputStream and FilterOutputStream provide additional processing like compression or encryption.
DataInputStream and DataOutputStream allow reading/writing primitive data types.
Example of an I/O Device in Java 1.1
Reading from a file:
import java.io.FileReader;
import java.io.IOException;
public class FileReaderExample {
public static void main(String[] args) {
try (FileReader fr = new FileReader("example.txt")) {
int character;
while ((character = fr.read()) != -1) {
System.out.print((char) character);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Conclusion In Java 1.1, an I/O device within the Java I/O API represents any external or internal source/destination of data. The API provides a stream-based architecture to handle files, console input/output, network communication, and serialized objects efficiently.