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.