Input/Output and File Handling
Java Programming (4343203)
Lecture 19
Unit 5: Advanced Java - I/O Operations
GTU Computer Engineering Semester 4
Learning Objectives
- Understand Java I/O stream hierarchy and classification
- Master byte streams and character streams
- Implement file operations (create, read, write, delete)
- Work with directories and file metadata
- Apply buffered I/O for performance optimization
- Implement object serialization and deserialization
Focus: Efficient data input/output operations and persistent storage using Java's comprehensive I/O framework.
Java I/O Stream Hierarchy
Stream Classification
- Byte Streams: Handle raw binary data (8-bit)
- Character Streams: Handle text data (16-bit Unicode)
- Input Streams: Read data from source
- Output Streams: Write data to destination
Key Differences
| Aspect | Byte Streams | Character Streams |
|---|---|---|
| Data Unit | 8-bit bytes | 16-bit characters |
| Base Classes | InputStream/OutputStream | Reader/Writer |
| Use Case | Binary data, images, audio | Text files, Unicode |
I/O Stream Hierarchy:
Byte Streams:
InputStream
├── FileInputStream
├── BufferedInputStream
├── DataInputStream
└── ObjectInputStream
OutputStream
├── FileOutputStream
├── BufferedOutputStream
├── DataOutputStream
└── ObjectOutputStream
Character Streams:
Reader
├── FileReader
├── BufferedReader
└── StringReader
Writer
├── FileWriter
├── BufferedWriter
├── PrintWriter
└── StringWriter
Byte Streams:
InputStream
├── FileInputStream
├── BufferedInputStream
├── DataInputStream
└── ObjectInputStream
OutputStream
├── FileOutputStream
├── BufferedOutputStream
├── DataOutputStream
└── ObjectOutputStream
Character Streams:
Reader
├── FileReader
├── BufferedReader
└── StringReader
Writer
├── FileWriter
├── BufferedWriter
├── PrintWriter
└── StringWriter
File Class for File and Directory Operations
import java.io.File;
import java.io.IOException;
import java.util.Date;
public class FileClassDemo {
public static void main(String[] args) {
System.out.println("=== File Class Demonstration ===\n");
// Create File objects
File file = new File("example.txt");
File directory = new File("testdir");
File nestedFile = new File(directory, "nested.txt");
demonstrateFileProperties(file);
demonstrateDirectoryOperations(directory);
demonstrateFileOperations(file, nestedFile);
}
private static void demonstrateFileProperties(File file) {
System.out.println("--- File Properties ---");
System.out.println("File name: " + file.getName());
System.out.println("Absolute path: " + file.getAbsolutePath());
System.out.println("Parent directory: " + file.getParent());
System.out.println("File exists: " + file.exists());
System.out.println("Is file: " + file.isFile());
System.out.println("Is directory: " + file.isDirectory());
System.out.println("Can read: " + file.canRead());
System.out.println("Can write: " + file.canWrite());
System.out.println("Can execute: " + file.canExecute());
System.out.println("Is hidden: " + file.isHidden());
if (file.exists()) {
System.out.println("File size: " + file.length() + " bytes");
System.out.println("Last modified: " + new Date(file.lastModified()));
}
System.out.println();
}
private static void demonstrateDirectoryOperations(File directory) {
System.out.println("--- Directory Operations ---");
// Create directory
if (!directory.exists()) {
boolean created = directory.mkdir(); // Creates single directory
// boolean created = directory.mkdirs(); // Creates parent directories too
System.out.println("Directory created: " + created);
} else {
System.out.println("Directory already exists");
}
// List directory contents
if (directory.exists() && directory.isDirectory()) {
System.out.println("Directory contents:");
String[] contents = directory.list();
if (contents != null) {
for (String item : contents) {
File itemFile = new File(directory, item);
System.out.printf(" %s %s%n",
itemFile.isDirectory() ? "[DIR]" : "[FILE]",
item);
}
} else {
System.out.println(" Directory is empty or cannot be read");
}
// Alternative: Get File objects
File[] files = directory.listFiles();
if (files != null) {
System.out.println("Total items: " + files.length);
}
}
System.out.println();
}
private static void demonstrateFileOperations(File file, File nestedFile) {
System.out.println("--- File Operations ---");
try {
// Create new file
if (!file.exists()) {
boolean created = file.createNewFile();
System.out.println("File created: " + created);
} else {
System.out.println("File already exists");
}
// Create nested file
if (!nestedFile.getParentFile().exists()) {
nestedFile.getParentFile().mkdirs();
}
if (!nestedFile.exists()) {
boolean nestedCreated = nestedFile.createNewFile();
System.out.println("Nested file created: " + nestedCreated);
}
// File permissions
file.setReadOnly();
System.out.println("File set to read-only");
file.setWritable(true);
System.out.println("File write permission restored");
// Copy file (using renameTo)
File copyFile = new File("example_copy.txt");
// Note: renameTo is platform dependent and may not work across filesystems
// File comparison
System.out.println("Files are same: " + file.equals(nestedFile));
} catch (IOException e) {
System.err.println("I/O error: " + e.getMessage());
}
System.out.println();
}
}
Byte Streams - FileInputStream and FileOutputStream
import java.io.*;
public class ByteStreamsDemo {
public static void main(String[] args) {
System.out.println("=== Byte Streams Demonstration ===\n");
String fileName = "binary_data.txt";
// Write data using FileOutputStream
writeDataUsingByteStream(fileName);
// Read data using FileInputStream
readDataUsingByteStream(fileName);
// Copy file using byte streams
copyFileUsingByteStreams(fileName, "binary_data_copy.txt");
// Demonstrate buffered streams
demonstrateBufferedByteStreams();
}
private static void writeDataUsingByteStream(String fileName) {
System.out.println("--- Writing Data Using FileOutputStream ---");
try (FileOutputStream fos = new FileOutputStream(fileName)) {
// Write single byte
fos.write(65); // ASCII value of 'A'
// Write byte array
String text = "Hello, Byte Streams!\n";
byte[] data = text.getBytes();
fos.write(data);
// Write part of byte array
String moreText = "Java I/O Programming";
byte[] moreData = moreText.getBytes();
fos.write(moreData, 0, 4); // Write "Java"
System.out.println("Data written to " + fileName);
} catch (IOException e) {
System.err.println("Error writing to file: " + e.getMessage());
}
}
private static void readDataUsingByteStream(String fileName) {
System.out.println("--- Reading Data Using FileInputStream ---");
try (FileInputStream fis = new FileInputStream(fileName)) {
System.out.println("File size: " + fis.available() + " bytes");
// Method 1: Read single byte
System.out.print("Reading byte by byte: ");
int byteData;
int count = 0;
while ((byteData = fis.read()) != -1 && count < 5) {
System.out.print((char) byteData);
count++;
}
System.out.println();
// Reset for next read method
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
}
// Method 2: Read entire file into byte array
try (FileInputStream fis = new FileInputStream(fileName)) {
byte[] buffer = new byte[fis.available()];
int bytesRead = fis.read(buffer);
System.out.println("Bytes read: " + bytesRead);
System.out.println("Content as string: " + new String(buffer));
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
}
// Method 3: Read with buffer
try (FileInputStream fis = new FileInputStream(fileName)) {
byte[] buffer = new byte[10]; // Small buffer for demonstration
int bytesRead;
System.out.print("Reading with buffer: ");
while ((bytesRead = fis.read(buffer)) != -1) {
System.out.print(new String(buffer, 0, bytesRead));
}
System.out.println();
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
}
System.out.println();
}
private static void copyFileUsingByteStreams(String sourceFile, String destFile) {
System.out.println("--- Copying File Using Byte Streams ---");
try (FileInputStream fis = new FileInputStream(sourceFile);
FileOutputStream fos = new FileOutputStream(destFile)) {
byte[] buffer = new byte[1024]; // 1KB buffer
int bytesRead;
int totalBytes = 0;
while ((bytesRead = fis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
totalBytes += bytesRead;
}
System.out.println("File copied successfully");
System.out.println("Total bytes copied: " + totalBytes);
} catch (IOException e) {
System.err.println("Error copying file: " + e.getMessage());
}
System.out.println();
}
private static void demonstrateBufferedByteStreams() {
System.out.println("--- Buffered Byte Streams ---");
String fileName = "buffered_test.txt";
// Write using BufferedOutputStream
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(fileName))) {
String data = "Buffered streams improve performance by reducing system calls.\n";
for (int i = 0; i < 5; i++) {
bos.write(data.getBytes());
}
// Flush is automatic when closing, but can be done manually
bos.flush();
System.out.println("Data written using BufferedOutputStream");
} catch (IOException e) {
System.err.println("Error with buffered output: " + e.getMessage());
}
// Read using BufferedInputStream
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(fileName))) {
byte[] buffer = new byte[50];
int bytesRead;
System.out.println("Reading using BufferedInputStream:");
while ((bytesRead = bis.read(buffer)) != -1) {
System.out.print(new String(buffer, 0, bytesRead));
}
} catch (IOException e) {
System.err.println("Error with buffered input: " + e.getMessage());
}
System.out.println();
}
}
Character Streams - FileReader and FileWriter
import java.io.*;
public class CharacterStreamsDemo {
public static void main(String[] args) {
System.out.println("=== Character Streams Demonstration ===\n");
String fileName = "text_data.txt";
// Write data using FileWriter
writeDataUsingCharacterStream(fileName);
// Read data using FileReader
readDataUsingCharacterStream(fileName);
// Demonstrate BufferedReader and BufferedWriter
demonstrateBufferedCharacterStreams();
// Demonstrate PrintWriter
demonstratePrintWriter();
}
private static void writeDataUsingCharacterStream(String fileName) {
System.out.println("--- Writing Data Using FileWriter ---");
try (FileWriter fw = new FileWriter(fileName)) {
// Write single character
fw.write('H');
// Write string
fw.write("ello, Character Streams!\n");
// Write character array
char[] chars = {'J', 'a', 'v', 'a', ' '};
fw.write(chars);
// Write part of string
String text = "I/O Programming is powerful!";
fw.write(text, 0, 3); // Write "I/O"
fw.write("\n");
// Write multiple lines
String[] lines = {
"Line 1: Introduction to I/O",
"Line 2: Character streams handle Unicode",
"Line 3: Perfect for text processing"
};
for (String line : lines) {
fw.write(line + "\n");
}
System.out.println("Text data written to " + fileName);
} catch (IOException e) {
System.err.println("Error writing to file: " + e.getMessage());
}
}
private static void readDataUsingCharacterStream(String fileName) {
System.out.println("--- Reading Data Using FileReader ---");
// Method 1: Read character by character
try (FileReader fr = new FileReader(fileName)) {
System.out.print("First 20 characters: ");
int charData;
int count = 0;
while ((charData = fr.read()) != -1 && count < 20) {
System.out.print((char) charData);
count++;
}
System.out.println();
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
}
// Method 2: Read into character array
try (FileReader fr = new FileReader(fileName)) {
char[] buffer = new char[50];
int charsRead = fr.read(buffer);
System.out.println("Characters read: " + charsRead);
System.out.println("Content: " + new String(buffer, 0, charsRead));
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
}
System.out.println();
}
private static void demonstrateBufferedCharacterStreams() {
System.out.println("--- Buffered Character Streams ---");
String fileName = "buffered_text.txt";
// Write using BufferedWriter
try (BufferedWriter bw = new BufferedWriter(new FileWriter(fileName))) {
bw.write("BufferedWriter improves performance");
bw.newLine(); // Platform-independent line separator
bw.write("It reduces the number of system calls");
bw.newLine();
bw.write("Especially useful for writing multiple lines");
System.out.println("Data written using BufferedWriter");
} catch (IOException e) {
System.err.println("Error with buffered writer: " + e.getMessage());
}
// Read using BufferedReader
try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
System.out.println("Reading using BufferedReader:");
String line;
int lineNumber = 1;
while ((line = br.readLine()) != null) {
System.out.println("Line " + lineNumber + ": " + line);
lineNumber++;
}
} catch (IOException e) {
System.err.println("Error with buffered reader: " + e.getMessage());
}
System.out.println();
}
private static void demonstratePrintWriter() {
System.out.println("--- PrintWriter Demonstration ---");
String fileName = "print_writer_demo.txt";
try (PrintWriter pw = new PrintWriter(new FileWriter(fileName))) {
// PrintWriter provides convenient methods
pw.println("PrintWriter is very convenient for formatted output");
pw.printf("Formatted number: %.2f%n", 3.14159);
pw.printf("Formatted string: %s has %d characters%n", "Java", 4);
// Write different data types
pw.println(42);
pw.println(true);
pw.println('X');
// Check for errors (PrintWriter doesn't throw exceptions)
if (pw.checkError()) {
System.err.println("An error occurred while writing");
} else {
System.out.println("Data written using PrintWriter");
}
} catch (IOException e) {
System.err.println("Error with PrintWriter: " + e.getMessage());
}
// Read and display the content
try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
System.out.println("Content written by PrintWriter:");
String line;
while ((line = br.readLine()) != null) {
System.out.println(" " + line);
}
} catch (IOException e) {
System.err.println("Error reading PrintWriter output: " + e.getMessage());
}
System.out.println();
}
}
Data Streams for Primitive Types
import java.io.*;
public class DataStreamsDemo {
public static void main(String[] args) {
System.out.println("=== Data Streams Demonstration ===\n");
String fileName = "primitive_data.dat";
// Write primitive data
writePrimitiveData(fileName);
// Read primitive data
readPrimitiveData(fileName);
}
private static void writePrimitiveData(String fileName) {
System.out.println("--- Writing Primitive Data ---");
try (DataOutputStream dos = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(fileName)))) {
// Write different primitive types
dos.writeBoolean(true);
dos.writeByte(127);
dos.writeShort(32767);
dos.writeInt(2147483647);
dos.writeLong(9223372036854775807L);
dos.writeFloat(3.14159f);
dos.writeDouble(2.718281828459);
dos.writeChar('J');
dos.writeUTF("Hello, DataOutputStream!"); // Modified UTF-8
// Write arrays
int[] numbers = {1, 2, 3, 4, 5};
dos.writeInt(numbers.length); // Write array length first
for (int num : numbers) {
dos.writeInt(num);
}
// Write a string array
String[] words = {"Java", "I/O", "Streams", "Data"};
dos.writeInt(words.length);
for (String word : words) {
dos.writeUTF(word);
}
System.out.println("Primitive data written to " + fileName);
} catch (IOException e) {
System.err.println("Error writing primitive data: " + e.getMessage());
}
}
private static void readPrimitiveData(String fileName) {
System.out.println("--- Reading Primitive Data ---");
try (DataInputStream dis = new DataInputStream(
new BufferedInputStream(new FileInputStream(fileName)))) {
// Read in the same order as written
boolean boolValue = dis.readBoolean();
byte byteValue = dis.readByte();
short shortValue = dis.readShort();
int intValue = dis.readInt();
long longValue = dis.readLong();
float floatValue = dis.readFloat();
double doubleValue = dis.readDouble();
char charValue = dis.readChar();
String stringValue = dis.readUTF();
// Display the values
System.out.println("Boolean: " + boolValue);
System.out.println("Byte: " + byteValue);
System.out.println("Short: " + shortValue);
System.out.println("Int: " + intValue);
System.out.println("Long: " + longValue);
System.out.println("Float: " + floatValue);
System.out.println("Double: " + doubleValue);
System.out.println("Char: " + charValue);
System.out.println("String: " + stringValue);
// Read array
int arrayLength = dis.readInt();
int[] numbers = new int[arrayLength];
for (int i = 0; i < arrayLength; i++) {
numbers[i] = dis.readInt();
}
System.out.print("Integer array: ");
for (int num : numbers) {
System.out.print(num + " ");
}
System.out.println();
// Read string array
int stringArrayLength = dis.readInt();
String[] words = new String[stringArrayLength];
for (int i = 0; i < stringArrayLength; i++) {
words[i] = dis.readUTF();
}
System.out.print("String array: ");
for (String word : words) {
System.out.print(word + " ");
}
System.out.println();
} catch (IOException e) {
System.err.println("Error reading primitive data: " + e.getMessage());
}
System.out.println();
}
}
// Student class for object demonstration
class Student implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private double gpa;
public Student(String name, int age, double gpa) {
this.name = name;
this.age = age;
this.gpa = gpa;
}
@Override
public String toString() {
return String.format("Student{name='%s', age=%d, gpa=%.2f}", name, age, gpa);
}
// Getters
public String getName() { return name; }
public int getAge() { return age; }
public double getGpa() { return gpa; }
}
Object Serialization and Deserialization
import java.io.*;
import java.util.*;
public class SerializationDemo {
public static void main(String[] args) {
System.out.println("=== Object Serialization Demonstration ===\n");
String fileName = "students.ser";
// Create sample data
List students = createSampleStudents();
// Serialize objects
serializeObjects(students, fileName);
// Deserialize objects
deserializeObjects(fileName);
// Demonstrate custom serialization
demonstrateCustomSerialization();
}
private static List createSampleStudents() {
List students = new ArrayList<>();
students.add(new Student("Alice Johnson", 20, 3.8));
students.add(new Student("Bob Smith", 19, 3.6));
students.add(new Student("Charlie Brown", 21, 3.9));
students.add(new Student("Diana Prince", 20, 3.7));
return students;
}
private static void serializeObjects(List students, String fileName) {
System.out.println("--- Serializing Objects ---");
try (ObjectOutputStream oos = new ObjectOutputStream(
new BufferedOutputStream(new FileOutputStream(fileName)))) {
// Serialize the entire list
oos.writeObject(students);
// Serialize individual objects
oos.writeInt(students.size());
for (Student student : students) {
oos.writeObject(student);
}
// Serialize other data types
oos.writeObject(new Date());
oos.writeObject("Serialization timestamp");
System.out.println("Objects serialized to " + fileName);
System.out.println("Serialized " + students.size() + " students");
} catch (IOException e) {
System.err.println("Error serializing objects: " + e.getMessage());
}
}
@SuppressWarnings("unchecked")
private static void deserializeObjects(String fileName) {
System.out.println("--- Deserializing Objects ---");
try (ObjectInputStream ois = new ObjectInputStream(
new BufferedInputStream(new FileInputStream(fileName)))) {
// Deserialize the list
List studentList = (List) ois.readObject();
System.out.println("Deserialized student list:");
for (Student student : studentList) {
System.out.println(" " + student);
}
// Deserialize individual objects
int count = ois.readInt();
System.out.println("\nDeserializing " + count + " individual students:");
for (int i = 0; i < count; i++) {
Student student = (Student) ois.readObject();
System.out.println(" " + (i + 1) + ". " + student);
}
// Deserialize other objects
Date timestamp = (Date) ois.readObject();
String message = (String) ois.readObject();
System.out.println("\nTimestamp: " + timestamp);
System.out.println("Message: " + message);
} catch (IOException | ClassNotFoundException e) {
System.err.println("Error deserializing objects: " + e.getMessage());
}
System.out.println();
}
private static void demonstrateCustomSerialization() {
System.out.println("--- Custom Serialization ---");
String fileName = "custom_serialization.ser";
try {
// Create a custom serializable object
BankAccount account = new BankAccount("12345", "John Doe", 5000.0, "secret123");
System.out.println("Original account: " + account);
// Serialize
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName))) {
oos.writeObject(account);
System.out.println("Account serialized");
}
// Deserialize
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName))) {
BankAccount deserializedAccount = (BankAccount) ois.readObject();
System.out.println("Deserialized account: " + deserializedAccount);
}
} catch (IOException | ClassNotFoundException e) {
System.err.println("Error with custom serialization: " + e.getMessage());
}
}
}
// Custom serializable class with sensitive data
class BankAccount implements Serializable {
private static final long serialVersionUID = 2L;
private String accountNumber;
private String holderName;
private double balance;
private transient String pin; // transient = won't be serialized
public BankAccount(String accountNumber, String holderName, double balance, String pin) {
this.accountNumber = accountNumber;
this.holderName = holderName;
this.balance = balance;
this.pin = pin;
}
// Custom serialization method
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject(); // Serialize non-transient fields
// Custom logic: encrypt PIN before serialization (simplified)
String encryptedPin = "encrypted_" + pin;
out.writeObject(encryptedPin);
System.out.println("Custom writeObject called - PIN encrypted");
}
// Custom deserialization method
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // Deserialize non-transient fields
// Custom logic: decrypt PIN after deserialization (simplified)
String encryptedPin = (String) in.readObject();
this.pin = encryptedPin.replace("encrypted_", "");
System.out.println("Custom readObject called - PIN decrypted");
}
@Override
public String toString() {
return String.format("BankAccount{accountNumber='%s', holderName='%s', balance=%.2f, pin='%s'}",
accountNumber, holderName, balance, pin != null ? "****" : "null");
}
}
GTU Previous Year Question (Summer 2022)
Q: Write a Java program to demonstrate file operations. The program should create a text file, write student information (name, roll number, marks) to the file, read the file content, and display it. Also implement functionality to append new student data to the existing file.
Solution:
import java.io.*;
import java.util.*;
// Student class to represent student data
class StudentInfo {
private String name;
private String rollNumber;
private double marks;
public StudentInfo(String name, String rollNumber, double marks) {
this.name = name;
this.rollNumber = rollNumber;
this.marks = marks;
}
// Convert to file format string
public String toFileString() {
return String.format("%s|%s|%.2f", name, rollNumber, marks);
}
// Create from file format string
public static StudentInfo fromFileString(String fileString) {
String[] parts = fileString.split("\\|");
if (parts.length == 3) {
return new StudentInfo(parts[0], parts[1], Double.parseDouble(parts[2]));
}
return null;
}
@Override
public String toString() {
return String.format("Name: %-20s | Roll: %-10s | Marks: %6.2f", name, rollNumber, marks);
}
// Getters
public String getName() { return name; }
public String getRollNumber() { return rollNumber; }
public double getMarks() { return marks; }
}
public class FileOperationsDemo {
private static final String FILENAME = "students.txt";
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("=== Student File Operations System ===\n");
boolean running = true;
while (running) {
displayMenu();
int choice = getChoice();
switch (choice) {
case 1:
createAndWriteFile();
break;
case 2:
readAndDisplayFile();
break;
case 3:
appendStudentData();
break;
case 4:
searchStudent();
break;
case 5:
displayStatistics();
break;
case 6:
backupFile();
break;
case 7:
running = false;
System.out.println("Program terminated.");
break;
default:
System.out.println("Invalid choice! Please try again.");
}
if (running) {
System.out.println("\nPress Enter to continue...");
scanner.nextLine();
}
}
scanner.close();
}
private static void displayMenu() {
System.out.println("\n" + "=".repeat(50));
System.out.println("STUDENT MANAGEMENT SYSTEM");
System.out.println("=".repeat(50));
System.out.println("1. Create new file and add students");
System.out.println("2. Read and display all students");
System.out.println("3. Append new student data");
System.out.println("4. Search for a student");
System.out.println("5. Display statistics");
System.out.println("6. Backup file");
System.out.println("7. Exit");
System.out.println("=".repeat(50));
System.out.print("Enter your choice (1-7): ");
}
private static int getChoice() {
try {
int choice = Integer.parseInt(scanner.nextLine().trim());
return choice;
} catch (NumberFormatException e) {
return -1; // Invalid choice
}
}
private static void createAndWriteFile() {
System.out.println("\n--- Create New File and Add Students ---");
List students = new ArrayList<>();
System.out.print("How many students do you want to add? ");
int count;
try {
count = Integer.parseInt(scanner.nextLine().trim());
} catch (NumberFormatException e) {
System.out.println("Invalid number! Using default of 3.");
count = 3;
}
// Collect student information
for (int i = 1; i <= count; i++) {
System.out.println("\nEnter details for Student " + i + ":");
System.out.print("Name: ");
String name = scanner.nextLine().trim();
System.out.print("Roll Number: ");
String rollNumber = scanner.nextLine().trim();
System.out.print("Marks: ");
double marks;
try {
marks = Double.parseDouble(scanner.nextLine().trim());
} catch (NumberFormatException e) {
System.out.println("Invalid marks! Using 0.0");
marks = 0.0;
}
students.add(new StudentInfo(name, rollNumber, marks));
}
// Write to file using FileWriter (character stream)
try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILENAME))) {
// Write header
writer.write("# Student Information File");
writer.newLine();
writer.write("# Format: Name|RollNumber|Marks");
writer.newLine();
writer.write("# Created on: " + new Date());
writer.newLine();
writer.newLine();
// Write student data
for (StudentInfo student : students) {
writer.write(student.toFileString());
writer.newLine();
}
System.out.println("\n✓ File created successfully!");
System.out.println("✓ " + students.size() + " students written to " + FILENAME);
} catch (IOException e) {
System.err.println("✗ Error creating file: " + e.getMessage());
}
}
private static void readAndDisplayFile() {
System.out.println("\n--- Reading and Displaying All Students ---");
File file = new File(FILENAME);
if (!file.exists()) {
System.out.println("✗ File " + FILENAME + " does not exist!");
System.out.println(" Please create the file first using option 1.");
return;
}
try (BufferedReader reader = new BufferedReader(new FileReader(FILENAME))) {
String line;
List students = new ArrayList<>();
int lineNumber = 0;
System.out.println("File Contents:");
System.out.println("-".repeat(80));
while ((line = reader.readLine()) != null) {
lineNumber++;
// Skip comments and empty lines
if (line.startsWith("#") || line.trim().isEmpty()) {
System.out.println("Line " + lineNumber + ": " + line);
continue;
}
// Parse student data
StudentInfo student = StudentInfo.fromFileString(line);
if (student != null) {
students.add(student);
System.out.println("Line " + lineNumber + ": " + line);
} else {
System.out.println("Line " + lineNumber + ": [Invalid format] " + line);
}
}
System.out.println("-".repeat(80));
// Display formatted student information
if (!students.isEmpty()) {
System.out.println("\nFormatted Student Information:");
System.out.println("=".repeat(80));
System.out.printf("%-4s | %-20s | %-10s | %-8s%n", "No.", "Name", "Roll No.", "Marks");
System.out.println("-".repeat(80));
for (int i = 0; i < students.size(); i++) {
StudentInfo student = students.get(i);
System.out.printf("%-4d | %-20s | %-10s | %8.2f%n",
i + 1, student.getName(), student.getRollNumber(), student.getMarks());
}
System.out.println("=".repeat(80));
System.out.println("Total students: " + students.size());
} else {
System.out.println("\nNo valid student records found in the file.");
}
} catch (IOException e) {
System.err.println("✗ Error reading file: " + e.getMessage());
}
}
}
Append and Search Implementation:
private static void appendStudentData() {
System.out.println("\n--- Append New Student Data ---");
File file = new File(FILENAME);
if (!file.exists()) {
System.out.println("✗ File " + FILENAME + " does not exist!");
System.out.println(" Please create the file first using option 1.");
return;
}
System.out.print("How many students do you want to add? ");
int count;
try {
count = Integer.parseInt(scanner.nextLine().trim());
} catch (NumberFormatException e) {
System.out.println("Invalid number! Using default of 1.");
count = 1;
}
// Collect new student information
List newStudents = new ArrayList<>();
for (int i = 1; i <= count; i++) {
System.out.println("\nEnter details for new Student " + i + ":");
System.out.print("Name: ");
String name = scanner.nextLine().trim();
System.out.print("Roll Number: ");
String rollNumber = scanner.nextLine().trim();
System.out.print("Marks: ");
double marks;
try {
marks = Double.parseDouble(scanner.nextLine().trim());
} catch (NumberFormatException e) {
System.out.println("Invalid marks! Using 0.0");
marks = 0.0;
}
newStudents.add(new StudentInfo(name, rollNumber, marks));
}
// Append to file using FileWriter with append mode
try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILENAME, true))) {
for (StudentInfo student : newStudents) {
writer.write(student.toFileString());
writer.newLine();
}
System.out.println("\n✓ " + newStudents.size() + " students appended successfully!");
} catch (IOException e) {
System.err.println("✗ Error appending to file: " + e.getMessage());
}
}
private static void searchStudent() {
System.out.println("\n--- Search for Student ---");
File file = new File(FILENAME);
if (!file.exists()) {
System.out.println("✗ File " + FILENAME + " does not exist!");
return;
}
System.out.println("Search by:");
System.out.println("1. Name");
System.out.println("2. Roll Number");
System.out.print("Enter choice (1 or 2): ");
int searchType;
try {
searchType = Integer.parseInt(scanner.nextLine().trim());
} catch (NumberFormatException e) {
searchType = 1;
}
System.out.print("Enter search term: ");
String searchTerm = scanner.nextLine().trim().toLowerCase();
try (BufferedReader reader = new BufferedReader(new FileReader(FILENAME))) {
String line;
List foundStudents = new ArrayList<>();
while ((line = reader.readLine()) != null) {
// Skip comments and empty lines
if (line.startsWith("#") || line.trim().isEmpty()) {
continue;
}
StudentInfo student = StudentInfo.fromFileString(line);
if (student != null) {
boolean matches = false;
if (searchType == 1) {
matches = student.getName().toLowerCase().contains(searchTerm);
} else {
matches = student.getRollNumber().toLowerCase().contains(searchTerm);
}
if (matches) {
foundStudents.add(student);
}
}
}
// Display search results
if (foundStudents.isEmpty()) {
System.out.println("\n✗ No students found matching: " + searchTerm);
} else {
System.out.println("\n✓ Found " + foundStudents.size() + " student(s):");
System.out.println("=".repeat(80));
for (int i = 0; i < foundStudents.size(); i++) {
System.out.println((i + 1) + ". " + foundStudents.get(i));
}
System.out.println("=".repeat(80));
}
} catch (IOException e) {
System.err.println("✗ Error searching file: " + e.getMessage());
}
}
private static void displayStatistics() {
System.out.println("\n--- File Statistics ---");
File file = new File(FILENAME);
if (!file.exists()) {
System.out.println("✗ File " + FILENAME + " does not exist!");
return;
}
try (BufferedReader reader = new BufferedReader(new FileReader(FILENAME))) {
String line;
List students = new ArrayList<>();
while ((line = reader.readLine()) != null) {
if (line.startsWith("#") || line.trim().isEmpty()) {
continue;
}
StudentInfo student = StudentInfo.fromFileString(line);
if (student != null) {
students.add(student);
}
}
if (students.isEmpty()) {
System.out.println("✗ No valid student records found.");
return;
}
// Calculate statistics
double totalMarks = 0;
double maxMarks = Double.MIN_VALUE;
double minMarks = Double.MAX_VALUE;
StudentInfo topStudent = null;
StudentInfo lowStudent = null;
for (StudentInfo student : students) {
double marks = student.getMarks();
totalMarks += marks;
if (marks > maxMarks) {
maxMarks = marks;
topStudent = student;
}
if (marks < minMarks) {
minMarks = marks;
lowStudent = student;
}
}
double averageMarks = totalMarks / students.size();
// Display statistics
System.out.println("=".repeat(80));
System.out.printf("Total Students : %d%n", students.size());
System.out.printf("Average Marks : %.2f%n", averageMarks);
System.out.printf("Highest Marks : %.2f%n", maxMarks);
System.out.printf("Lowest Marks : %.2f%n", minMarks);
System.out.printf("Top Performer : %s (%.2f)%n", topStudent.getName(), topStudent.getMarks());
System.out.printf("Needs Improvement : %s (%.2f)%n", lowStudent.getName(), lowStudent.getMarks());
// Grade distribution
int gradeA = 0, gradeB = 0, gradeC = 0, gradeD = 0, gradeF = 0;
for (StudentInfo student : students) {
double marks = student.getMarks();
if (marks >= 90) gradeA++;
else if (marks >= 80) gradeB++;
else if (marks >= 70) gradeC++;
else if (marks >= 60) gradeD++;
else gradeF++;
}
System.out.println("-".repeat(40));
System.out.println("Grade Distribution:");
System.out.printf("A (90-100) : %d students%n", gradeA);
System.out.printf("B (80-89) : %d students%n", gradeB);
System.out.printf("C (70-79) : %d students%n", gradeC);
System.out.printf("D (60-69) : %d students%n", gradeD);
System.out.printf("F (0-59) : %d students%n", gradeF);
System.out.println("=".repeat(80));
} catch (IOException e) {
System.err.println("✗ Error reading file for statistics: " + e.getMessage());
}
}
private static void backupFile() {
System.out.println("\n--- Backup File ---");
File sourceFile = new File(FILENAME);
if (!sourceFile.exists()) {
System.out.println("✗ File " + FILENAME + " does not exist!");
return;
}
String backupFileName = "backup_" + System.currentTimeMillis() + "_" + FILENAME;
File backupFile = new File(backupFileName);
try (BufferedReader reader = new BufferedReader(new FileReader(sourceFile));
BufferedWriter writer = new BufferedWriter(new FileWriter(backupFile))) {
String line;
int linesCopied = 0;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine();
linesCopied++;
}
System.out.println("✓ File backed up successfully!");
System.out.println("✓ Backup file: " + backupFileName);
System.out.println("✓ Lines copied: " + linesCopied);
System.out.println("✓ Backup size: " + backupFile.length() + " bytes");
} catch (IOException e) {
System.err.println("✗ Error creating backup: " + e.getMessage());
}
}
}
Solution Features:
- Complete file operations: create, read, write, append
- Menu-driven interface for easy interaction
- Student data management with search functionality
- File statistics and grade distribution analysis
- Backup functionality for data safety
- Error handling and input validation
🧪 Hands-on Lab Exercise
Lab 19: Employee Record Management System
Task: Create a comprehensive employee record management system using various I/O streams for different data operations.
Requirements:
- Use character streams for employee text data (name, department, email)
- Use data streams for numeric data (salary, employee ID, hire date)
- Implement object serialization for complete employee objects
- Create file backup and restore functionality
- Implement CSV import/export capabilities
- Add logging functionality using file I/O
Challenge: Implement a transaction log system that records all file operations with rollback capability in case of failures.
📚 Lecture Summary
Key I/O Concepts Covered
- Java I/O stream hierarchy and classification
- Byte streams (InputStream/OutputStream)
- Character streams (Reader/Writer)
- File class for file system operations
- Buffered streams for performance
- Object serialization/deserialization
Best Practices
- Use try-with-resources for automatic stream closure
- Choose appropriate stream type for data
- Use buffered streams for better performance
- Handle IOException properly
- Use character streams for text data
- Implement Serializable for object persistence
🎯 Next Lecture Preview
Lecture 20: Lambda Expressions and Functional Interfaces
- Functional programming concepts in Java
- Lambda expression syntax and usage
- Built-in functional interfaces
- Stream API and functional operations

