I/O in Java
Input/Output (I/O) in Java is a mechanism that allows programs to interact with the outside world. This can include reading and writing files, reading from and writing to the console, interacting with network resources, or handling data streams. Java provides a robust and flexible I/O API in the java.io
package to work with various I/O operations.
Java I/O can be categorized into two types:
- Byte Stream: Used for handling I/O of raw binary data (e.g., images, audio files, etc.).
- Character Stream: Used for handling I/O of characters (e.g., text files) and ensures proper encoding and decoding of text.
Byte Streams
Byte streams are used to perform input and output of 8-bit bytes. These are suitable for handling I/O of raw binary data like image files, audio files, etc.
Key Classes in Byte Streams:
- InputStream: This is the abstract class for all byte input streams. It has various subclasses like
FileInputStream
,BufferedInputStream
, etc. - OutputStream: This is the abstract class for all byte output streams. It has various subclasses like
FileOutputStream
,BufferedOutputStream
, etc.
Example: Reading and Writing a File Using Byte Streams
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamExample {
public static void main(String[] args) {
// File to read and write
String inputFile = "input.txt";
String outputFile = "output.txt";
try (FileInputStream fis = new FileInputStream(inputFile);
FileOutputStream fos = new FileOutputStream(outputFile)) {
int byteData;
while ((byteData = fis.read()) != -1) { // Read byte by byte
fos.write(byteData); // Write byte by byte
}
System.out.println("File copied successfully.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Explanation:
FileInputStream
: Reads bytes from the specified file.FileOutputStream
: Writes bytes to the specified file.- The program reads bytes from the input file and writes them one by one to the output file.
Character Streams
Character streams are designed for handling the input and output of 16-bit Unicode characters, and they are particularly useful for text files. These streams ensure proper encoding and decoding of text files, which is important for internationalization.
Key Classes in Character Streams:
- Reader: The abstract class for all character input streams. It has subclasses like
FileReader
,BufferedReader
, etc. - Writer: The abstract class for all character output streams. It has subclasses like
FileWriter
,BufferedWriter
, etc.
Example: Reading and Writing Text Files Using Character Streams
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
public class CharacterStreamExample {
public static void main(String[] args) {
String inputFile = "input.txt";
String outputFile = "output.txt";
try (BufferedReader br = new BufferedReader(new FileReader(inputFile));
BufferedWriter bw = new BufferedWriter(new FileWriter(outputFile))) {
String line;
while ((line = br.readLine()) != null) {
bw.write(line); // Write each line to the output file
bw.newLine(); // Add a newline after each line
}
System.out.println("File copied successfully.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Explanation:
FileReader
: Reads characters from the specified file.FileWriter
: Writes characters to the specified file.BufferedReader
: Reads text from a character-based input stream, buffering characters to efficiently read characters, arrays, and lines.BufferedWriter
: Writes text to a character-based output stream, buffering characters to provide efficient writing of text.
Buffered Streams
Buffered streams provide a performance boost by reducing the number of read/write operations. Instead of reading/writing data byte by byte or character by character, buffered streams use a larger buffer and process data in chunks.
Example: Using Buffered Streams for Efficiency
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedStreamExample {
public static void main(String[] args) {
String inputFile = "input.txt";
String outputFile = "output.txt";
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inputFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outputFile))) {
int byteData;
while ((byteData = bis.read()) != -1) {
bos.write(byteData); // Write data in buffered chunks
}
System.out.println("File copied using buffered streams.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Explanation:
BufferedInputStream
: Reads data from the input stream in larger chunks.BufferedOutputStream
: Writes data to the output stream in larger chunks.- Buffered streams help improve performance, especially when reading or writing large files.
Object Streams
Object streams are used for reading and writing Java objects (i.e., serializing and deserializing objects). These streams handle the conversion between Java objects and streams of bytes.
Key Classes in Object Streams:
- ObjectInputStream: Deserializes objects (i.e., reads them from a stream).
- ObjectOutputStream: Serializes objects (i.e., writes them to a stream).
Example: Writing and Reading Objects Using Object Streams
import java.io.*;
class Person implements Serializable {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class ObjectStreamExample {
public static void main(String[] args) {
Person person = new Person("John Doe", 30);
String fileName = "person.ser";
// Writing object to a file
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName))) {
oos.writeObject(person);
System.out.println("Object has been serialized.");
} catch (IOException e) {
e.printStackTrace();
}
// Reading object from a file
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName))) {
Person deserializedPerson = (Person) ois.readObject();
System.out.println("Object has been deserialized.");
System.out.println("Name: " + deserializedPerson.name + ", Age: " + deserializedPerson.age);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Explanation:
Serializable
: A marker interface that indicates a class can be serialized.ObjectOutputStream
: Writes a Java object to a file (serializes it).ObjectInputStream
: Reads a serialized object from a file (deserializes it).
File I/O Operations Using NIO (New I/O)
Java introduced the NIO (New I/O) API in Java 1.4, which provides more efficient and scalable I/O operations. The NIO API is based on buffers and channels and is particularly useful for handling large files, network operations, or I/O intensive tasks.
Key NIO Classes:
- Path: Represents a path in the file system.
- Files: Contains utility methods for file operations.
- FileChannel: Allows reading and writing data to files using channels.
- ByteBuffer: A container for binary data in NIO.
Example: Reading and Writing Files Using NIO
import java.nio.file.*;
import java.io.IOException;
public class NIOExample {
public static void main(String[] args) {
Path inputPath = Paths.get("input.txt");
Path outputPath = Paths.get("output.txt");
try {
// Reading all bytes from input file
byte[] fileBytes = Files.readAllBytes(inputPath);
// Writing bytes to output file
Files.write(outputPath, fileBytes);
System.out.println("File copied using NIO.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Explanation:
Paths.get()
: Returns aPath
object that represents the file location.Files.readAllBytes()
: Reads all bytes from the input file into a byte array.Files.write()
: Writes the byte array to the output file.
Conclusion
Java I/O provides a comprehensive set of classes and interfaces for working with data streams, files, and other I/O resources. Some key points to remember:
- Byte Streams work with raw binary data, and Character Streams work with character data, ensuring proper encoding/decoding.
- Buffered streams improve I/O performance by reading and writing data in large chunks.
- Object Streams allow you to serialize and deserialize Java objects.
- NIO (New I/O) provides more efficient and scalable I/O operations using channels and buffers.
By using the appropriate stream types, you can efficiently handle different types of I/O operations in Java.