File I/O and Serialization
45 minFile I/O (Input/Output) enables Java applications to read from and write to files, enabling data persistence and external data processing. Java provides multiple APIs for file operations: traditional `java.io` classes (FileReader, FileWriter, BufferedReader), NIO.2 (Java 7+, Path, Files), and newer APIs. Understanding file I/O is essential for applications that need to store or process file data.
The NIO.2 package (Java 7+) provides modern file operations with better performance and more features than traditional I/O. The `Path` interface represents file system paths, and the `Files` utility class provides static methods for common operations: `readAllLines()`, `write()`, `copy()`, `move()`, `delete()`, and more. NIO.2 supports asynchronous I/O and better error handling. Understanding NIO.2 helps you write efficient, modern file I/O code.
Serialization converts objects into byte streams for storage or transmission over networks. Objects implement `Serializable` interface to enable serialization. `ObjectOutputStream` writes objects, and `ObjectInputStream` reads them. Serialization enables object persistence and remote method invocation. However, serialization has security concerns and versioning issues. Understanding serialization helps you persist objects when appropriate.
JSON (JavaScript Object Notation) is a popular data interchange format. Libraries like Jackson and Gson enable Java object-to-JSON conversion and vice versa. JSON is human-readable, language-independent, and widely used in web APIs. Modern applications often use JSON instead of Java serialization for data exchange. Understanding JSON processing helps you work with modern APIs and data formats.
Best practices include using NIO.2 for file operations (better performance), using try-with-resources for automatic resource management, handling I/O exceptions properly, using JSON for data interchange (more portable than serialization), and validating file paths and permissions. File I/O should handle errors gracefully and clean up resources. Understanding file I/O enables you to build applications that persist and process data effectively.
Key Concepts
- File I/O enables reading from and writing to files.
- NIO.2 provides modern file operations with better performance.
- Serialization converts objects to byte streams.
- JSON is a popular data interchange format.
- try-with-resources ensures proper resource cleanup.
Learning Objectives
Master
- Reading from and writing to files using NIO.2
- Working with serialization for object persistence
- Processing JSON data with libraries like Jackson
- Handling file I/O errors and resource management
Develop
- Data persistence and I/O thinking
- Understanding file operations and error handling
- Designing robust file processing applications
Tips
- Use NIO.2 (Files, Path) for modern file operations.
- Use try-with-resources for automatic resource cleanup.
- Use JSON for data interchange instead of Java serialization when possible.
- Handle I/O exceptions properly—they're common in file operations.
Common Pitfalls
- Not closing file streams, causing resource leaks.
- Not handling I/O exceptions, causing application crashes.
- Using Java serialization for cross-language data exchange.
- Not validating file paths, causing security issues.
Summary
- File I/O enables data persistence and file processing.
- NIO.2 provides modern, efficient file operations.
- Serialization enables object persistence.
- JSON is preferred for data interchange.
- Understanding file I/O enables data-driven applications.
Exercise
Create a program that demonstrates file operations, serialization, and JSON processing.
import java.io.*;
import java.nio.file.*;
import java.util.*;
import com.fasterxml.jackson.databind.ObjectMapper;
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private List<String> hobbies;
public Person(String name, int age, List<String> hobbies) {
this.name = name;
this.age = age;
this.hobbies = hobbies;
}
// Getters and setters
public String getName() { return name; }
public int getAge() { return age; }
public List<String> getHobbies() { return hobbies; }
@Override
public String toString() {
return String.format("Person{name='%s', age=%d, hobbies=%s}", name, age, hobbies);
}
}
public class FileIODemo {
public static void main(String[] args) {
try {
// Create sample data
List<Person> people = Arrays.asList(
new Person("Alice", 25, Arrays.asList("reading", "swimming")),
new Person("Bob", 30, Arrays.asList("gaming", "cooking"))
);
// Write to file using NIO.2
Path filePath = Paths.get("people.txt");
List<String> lines = new ArrayList<>();
for (Person person : people) {
lines.add(person.toString());
}
Files.write(filePath, lines);
System.out.println("Data written to file: " + filePath);
// Read from file
List<String> readLines = Files.readAllLines(filePath);
System.out.println("\nData read from file:");
readLines.forEach(System.out::println);
// Serialization
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("people.ser"))) {
oos.writeObject(people);
System.out.println("\nData serialized to people.ser");
}
// Deserialization
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("people.ser"))) {
@SuppressWarnings("unchecked")
List<Person> deserializedPeople = (List<Person>) ois.readObject();
System.out.println("\nDeserialized data:");
deserializedPeople.forEach(System.out::println);
}
// JSON processing (requires Jackson dependency)
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(people);
System.out.println("\nJSON representation:");
System.out.println(json);
} catch (Exception e) {
e.printStackTrace();
}
}
}