Skip to main content

11.2 File & I/O

Java File Handling: Reading and Writing Files, Working with Streams and Buffers, and Java NIO

Overview

File handling is essential for applications that need to read, write, or process data from external sources. Java provides traditional I/O methods for handling files as well as modern NIO (New I/O) techniques, which enhance performance and scalability. This guide covers reading and writing files, working with streams and buffers, and using Java NIO.


1. Reading and Writing Files

Java’s traditional I/O package (java.io) includes classes like FileReader, FileWriter, BufferedReader, and BufferedWriter for reading and writing text files.

Example: Reading a File with BufferedReader

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileReadExample {
public static void main(String[] args) {
try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

In this example, BufferedReader reads a file line by line, improving performance by buffering characters.

Example: Writing to a File with BufferedWriter

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class FileWriteExample {
public static void main(String[] args) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
writer.write("Hello, World!");
writer.newLine();
writer.write("Java File Handling Example");
} catch (IOException e) {
e.printStackTrace();
}
}
}

In this example, BufferedWriter writes text to a file, using newLine() to add line breaks.


2. Working with Streams and Buffers

Streams provide a way to read from or write to a data source continuously, while buffers optimize these operations by temporarily storing data.

Byte Streams

Byte streams read and write binary data, useful for handling image, audio, or binary files.

Example: Reading and Writing Binary Files

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class BinaryFileExample {
public static void main(String[] args) {
try (FileInputStream in = new FileInputStream("input.bin");
FileOutputStream out = new FileOutputStream("output.bin")) {

int data;
while ((data = in.read()) != -1) {
out.write(data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

Here, FileInputStream and FileOutputStream read and write binary data one byte at a time.

Character Streams

Character streams are used for text files, handling data as characters rather than bytes.

Example: Using BufferedReader and BufferedWriter for Character Streams

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CharacterStreamExample {
public static void main(String[] args) {
try (BufferedReader reader = new BufferedReader(new FileReader("source.txt"));
BufferedWriter writer = new BufferedWriter(new FileWriter("destination.txt"))) {

String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

This example reads and writes text files, with BufferedReader and BufferedWriter providing efficient data handling.


3. Using Java NIO for Modern File Handling

Java NIO (java.nio) offers advanced file handling techniques using the Path, Files, and FileChannel classes, enabling non-blocking operations.

Path and Files Classes

The Path and Files classes provide a simplified API for file manipulation, including file reading, writing, copying, and deleting.

Example: Reading a File with Files.readAllLines()

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

public class NIOReadExample {
public static void main(String[] args) {
Path path = Paths.get("example.txt");
try {
List<String> lines = Files.readAllLines(path);
lines.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
}

This example reads all lines of a file into a List using Files.readAllLines(), providing a convenient way to read entire files.

Example: Writing to a File with Files.write()

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

public class NIOWriteExample {
public static void main(String[] args) {
Path path = Paths.get("output.txt");
List<String> lines = Arrays.asList("Hello, NIO!", "Java Modern File Handling");

try {
Files.write(path, lines);
} catch (IOException e) {
e.printStackTrace();
}
}
}

In this example, Files.write() writes a list of strings to a file, replacing existing content.

FileChannel for Advanced File Handling

FileChannel provides fast, flexible file access and is suitable for large files or binary data.

Example: Copying a File with FileChannel

import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

public class FileChannelExample {
public static void main(String[] args) {
Path source = Path.of("source.bin");
Path destination = Path.of("destination.bin");

try (FileChannel sourceChannel = FileChannel.open(source, StandardOpenOption.READ);
FileChannel destChannel = FileChannel.open(destination, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {

sourceChannel.transferTo(0, sourceChannel.size(), destChannel);
} catch (IOException e) {
e.printStackTrace();
}
}
}

This example copies a binary file using FileChannel.transferTo(), an efficient method for large data transfers.


Summary

  • Reading and Writing Files: BufferedReader and BufferedWriter provide efficient text file handling, while FileInputStream and FileOutputStream handle binary data.
  • Streams and Buffers: Use character and byte streams for data, with buffers optimizing performance.
  • Java NIO: Path, Files, and FileChannel enable modern, high-performance file operations.

With these techniques, you can efficiently manage file handling in Java applications, ensuring data integrity, speed, and scalability.