Advanced Programming with JavaUnit 613 min read
File I/O, Serialization & Object Persistence in Java
Unit 6 of Advanced Programming with Java covers reading/writing files (text, binary), Java’s serialization mechanism, object persistence, and file handling best practices with hands-on examples and error-handling techniques.
TAKEAWAYS:
- Java’s
FileandFileInputStream/FileOutputStreamclasses handle file operations at the byte level, whileScanner/PrintWritersimplify text I/O. - Serialization converts objects into byte streams (via
Serializableinterface) for storage or network transfer, but requires all fields to be serializable. - Object persistence (saving/loading objects) uses serialization or databases; serialization is simpler but less flexible for complex queries.
- File handling errors (e.g.,
FileNotFoundException,IOException) must be caught explicitly; always close resources usingtry-with-resources. - Binary files (e.g., images) are read/written as byte arrays, while text files use character encodings (UTF-8 by default).
- Security risks in serialization include malicious object reconstruction; use
ObjectInputFilterto mitigate.
1. File I/O Basics: Reading and Writing Files
Java provides two primary approaches to file handling:
- Byte-level I/O (for binary files like images, executables):
FileInputStream/FileOutputStreamfor raw bytes.BufferedInputStream/BufferedOutputStreamfor efficiency.
- Character-level I/O (for text files):
Scanner(for reading) andPrintWriter(for writing) withFileobjects.- Supports encodings like UTF-8 (
Charset.forName("UTF-8")).
Key Classes and Methods
| Class/Interface | Purpose | Example Methods |
|---|---|---|
File |
Represents file/directory metadata (name, path, size). | exists(), createNewFile(), delete() |
FileInputStream |
Reads bytes from a file. | read(), read(byte[]) |
FileOutputStream |
Writes bytes to a file. | write(int), write(byte[]) |
Scanner |
Reads text from files/inputs. | nextLine(), nextInt(), useDelimiter() |
PrintWriter |
Writes formatted text to files. | println(), printf() |
BufferedReader/Writer |
Efficient line-by-line text I/O. | readLine(), newLine() |
Example: Writing to a Text File
import java.io.PrintWriter;
import java.io.File;
import java.io.IOException;
public class FileWriterExample {
public static void main(String[] args) {
try (PrintWriter writer = new PrintWriter(new File("data.txt"), "UTF-8")) {
writer.println("Hello, File I/O!");
writer.printf("Current time: %tT%n", System.currentTimeMillis());
} catch (IOException e) {
System.err.println("Error writing to file: " + e.getMessage());
}
}
}
Trace (State After Each Step):
| Step | Action | File data.txt Content |
Exception Thrown |
|---|---|---|---|
Before try |
Program starts. | (Empty) | None |
PrintWriter init |
Opens data.txt in write mode. |
(Empty) | None |
writer.println() |
Writes "Hello, File I/O!". | Hello, File I/O! |
None |
writer.printf() |
Writes formatted timestamp. | Hello, File I/O!<newline>Current time: ... |
None |
try block ends |
Auto-closes PrintWriter. |
(Content preserved) | None |
catch block |
(No exception) | None |
Visual: File Hierarchy
classDiagram
class File {
+String name
+String path
+boolean exists()
+boolean createNewFile()
}
class FileInputStream {
+int read()
+int read(byte[] b)
}
class PrintWriter {
+void println(String)
+void printf(String, Object...)
}
File --> FileInputStream : "Used to create"
File --> PrintWriter : "Used to create"2. Reading Binary Files (Images, Executables)
Binary files (e.g., .jpg, .exe) are read/written as byte arrays. Example: Reading an image file.
import java.io.FileInputStream;
import java.io.IOException;
public class BinaryFileReader {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("image.jpg")) {
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
System.out.println("Read " + buffer.length + " bytes.");
} catch (IOException e) {
System.err.println("Error: " + e.getMessage());
}
}
}
State After Each Step:
| Step | Action | buffer Content |
Exception Thrown |
|---|---|---|---|
Before try |
Program starts. | null |
None |
FileInputStream |
Opens image.jpg. |
null |
None |
fis.available() |
Returns file size (e.g., 1024 bytes). | null |
None |
fis.read(buffer) |
Fills buffer with file bytes. |
[byte[1024] of image data] |
None |
try block ends |
Auto-closes FileInputStream. |
[byte[1024]] (preserved) |
None |
Real-World Example: Daraz Order Processing Daraz stores user order data (e.g., product IDs, quantities) in binary files for faster access during peak hours. Binary files reduce parsing overhead compared to text files.
3. Serialization: Saving Objects to Files
Serialization converts an object’s state into a byte stream, enabling persistence or network transfer. Requires implementing Serializable.
Key Interfaces and Classes
| Interface/Class | Purpose |
|---|---|
Serializable |
Marker interface (no methods); enables serialization. |
ObjectOutputStream |
Writes serialized objects to a stream. |
ObjectInputStream |
Reads serialized objects from a stream. |
transient keyword |
Marks fields to exclude from serialization. |
Example: Serializing a Student Object
import java.io.*;
class Student implements Serializable {
private String name;
private transient int password; // Excluded from serialization
private static final long serialVersionUID = 1L; // For version control
public Student(String name, int password) {
this.name = name;
this.password = password;
}
}
public class SerializationExample {
public static void main(String[] args) {
Student student = new Student("Rohan", 12345);
// Serialize to file
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("student.ser"))) {
oos.writeObject(student);
System.out.println("Serialized data is saved in student.ser");
} catch (IOException e) {
e.printStackTrace();
}
// Deserialize from file
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("student.ser"))) {
Student loadedStudent = (Student) ois.readObject();
System.out.println("Deserialized: " + loadedStudent.name);
// password remains 0 (transient)
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
State After Serialization:
graph LR
A["Student Object"] -->|"serialized to"| B["student.ser (byte stream)"]
B -->|"deserialized into"| C["New Student Object"]
C --> D["name: Rohan"]
C --> E["password: 0 (transient)"]Visual: Serialization Process
sequenceDiagram
participant Student as Student Object
participant OOS as ObjectOutputStream
participant File as student.ser
participant OIS as ObjectInputStream
participant NewStudent as Deserialized Object
Student->>OOS: writeObject()
OOS->>File: Writes byte stream
File-->>OIS: Reads byte stream
OIS->>NewStudent: readObject()
Note right of NewStudent: password is 0 (transient)4. Object Persistence: Serialization vs. Databases
| Feature | Serialization | Database (e.g., JDBC) |
|---|---|---|
| Use Case | Simple object storage/retrieval. | Complex queries, relationships. |
| Performance | Fast for single objects. | Slower for simple CRUD. |
| Flexibility | Limited (no SQL queries). | Full query support (JOIN, WHERE). |
| Security | Vulnerable to malicious data. | ACID-compliant (transactions). |
| Example | Saving game progress. | Banking transactions (Nepal Rastra Bank). |
Real-World Example: eSewa Transaction Logs
eSewa serializes transaction records (e.g., Transaction{userID, amount, timestamp}) to files for offline processing. During high traffic, these files are later merged into a database for reporting.
5. Handling File I/O Exceptions
Common exceptions and best practices:
FileNotFoundException: File does not exist. Fix: Check file path or create the file first.IOException: General I/O errors (permission, disk full). Fix: Usetry-with-resourcesto auto-close streams.ClassNotFoundException: Deserializing unknown classes. Fix: EnsureserialVersionUIDmatches.
Example: Robust File Reading
import java.io.*;
public class RobustFileReader {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(
new FileReader("data.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
System.err.println("File not found. Creating a new one...");
try (PrintWriter pw = new PrintWriter("data.txt")) {
pw.println("Default content");
}
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
}
}
}
6. Advanced Topics: Custom Serialization
Override writeObject()/readObject() for control over serialization:
class BankAccount implements Serializable {
private String accountNumber;
private transient double balance; // Encrypted in file
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeDouble(encrypt(balance)); // Custom encryption
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
this.balance = decrypt(ois.readDouble());
}
private double encrypt(double value) { /* ... */ }
private double decrypt(double value) { /* ... */ }
}
Visual: Custom Serialization Flow
flowchart TD
A["BankAccount Object"] --> B["writeObject()"]
B --> C["Encrypt balance"]
C --> D["Write to stream"]
D --> E["File: encrypted.ser"]
E --> F["readObject()"]
F --> G["Decrypt balance"]
G --> H["New BankAccount Object"]In the Real World
Khalti Payment Records
- Idea Used: Serialization
- How: Khalti stores completed transactions (e.g.,
Transaction{id, amount, merchant}) as serialized objects in temporary files during peak hours (e.g., Dashain sales). These files are later merged into a database for reconciliation.
Nepal Telecom (NTC) Call Logs
- Idea Used: Binary File I/O
- How: NTC’s billing system reads binary call detail records (CDRs) from switches. Each CDR is a fixed-size binary block containing
callerID,duration, andtimestamp. Binary format minimizes storage and speeds up processing for millions of daily calls.
Pathao Driver Availability
- Idea Used: File I/O + Serialization
- How: Pathao’s backend serializes driver availability status (e.g.,
Driver{id, location, isAvailable}) to disk when the server restarts. This ensures drivers are quickly matched to riders without losing state during crashes.
Exam Tip
- File Paths: Always use absolute paths in exams (e.g.,
C:\\data\\file.txtor/home/user/file.txt). Relative paths may fail in automated grading. - Resource Management: Prefer
try-with-resourcesover manualclose()calls. Examiners check for auto-closing. - Serialization Pitfalls:
- Forgetting
implements Serializable→NotSerializableException. - Missing
serialVersionUID→InvalidClassExceptionduring deserialization. transientfields are excluded; explain why in answers.
- Forgetting
- Error Handling: Exams often test exception handling. Always catch
IOExceptionandClassNotFoundExceptionfor serialization. - Binary vs. Text Files:
- Binary: Use
FileInputStream/FileOutputStream+ byte arrays. - Text: Use
Scanner/PrintWriterwith encodings (e.g.,UTF-8).
- Binary: Use
- Worked Examples: Draw state diagrams (like the ones above) for:
- File content after each
write()/read(). - Object graph before/after serialization.
- File content after each
- Real-World Mapping: Relate examples to local apps (e.g., "How would you serialize a Daraz order for offline processing?").
Based on the PU BE Computer (PU) syllabus for Advanced Programming with Java (CMP228), unit 6.
Discussion
Loading…