Java Programming Language
Chapter 11: File Handling
Input/Output Operations in Java
Course: 4343203 - Java Programming
What We'll Cover
- File and Directory Operations
- Stream-based I/O
- Character and Byte Streams
- Buffered I/O
- Object Serialization
- NIO (New I/O) Overview
- File Exception Handling
- Best Practices
Java I/O Stream Hierarchy
File and Directory Operations
File class provides methods for file and directory manipulation
File Class Basics
Creating File Objects:
import java.io.File;
public class FileBasics {
public static void main(String[] args) {
// Different ways to create File objects
File file1 = new File("data.txt");
File file2 = new File("/home/user/documents/data.txt");
File file3 = new File("C:\\Users\\User\\data.txt");
// Using parent directory and filename
File parentDir = new File("/home/user/documents");
File file4 = new File(parentDir, "data.txt");
// Using File.separator for platform independence
String path = "documents" + File.separator + "data.txt";
File file5 = new File(path);
System.out.println("File separator: " + File.separator);
System.out.println("Path separator: " + File.pathSeparator);
// File information
System.out.println("Absolute path: " + file1.getAbsolutePath());
System.out.println("Parent: " + file1.getParent());
System.out.println("Name: " + file1.getName());
}
}
File Properties and Tests:
public class FileProperties {
public static void testFile(String filename) {
File file = new File(filename);
System.out.println("File: " + filename);
System.out.println("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("Size: " + file.length() + " bytes");
System.out.println("Last modified: " +
new Date(file.lastModified()));
}
System.out.println("------------------------");
}
public static void main(String[] args) {
testFile("data.txt");
testFile("documents");
testFile("nonexistent.txt");
}
}
File and Directory Operations
Creating Files and Directories:
import java.io.*;
public class FileOperations {
public static void main(String[] args) {
try {
// Create a new file
File newFile = new File("example.txt");
if (newFile.createNewFile()) {
System.out.println("File created: " + newFile.getName());
} else {
System.out.println("File already exists");
}
// Create directory
File dir = new File("myDirectory");
if (dir.mkdir()) {
System.out.println("Directory created: " + dir.getName());
}
// Create directory with parent directories
File nestedDir = new File("parent/child/grandchild");
if (nestedDir.mkdirs()) {
System.out.println("Nested directories created");
}
// Create temporary file
File tempFile = File.createTempFile("temp", ".txt");
System.out.println("Temp file: " + tempFile.getAbsolutePath());
tempFile.deleteOnExit(); // Delete when JVM exits
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Listing Directory Contents:
public class DirectoryListing {
public static void listDirectory(String dirPath) {
File directory = new File(dirPath);
if (!directory.exists()) {
System.out.println("Directory doesn't exist: " + dirPath);
return;
}
if (!directory.isDirectory()) {
System.out.println("Not a directory: " + dirPath);
return;
}
System.out.println("Contents of: " + directory.getAbsolutePath());
// List all files and directories
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
String type = file.isDirectory() ? "[DIR]" : "[FILE]";
System.out.println(type + " " + file.getName());
}
}
// List only files with specific extension
File[] txtFiles = directory.listFiles((dir, name) ->
name.toLowerCase().endsWith(".txt"));
System.out.println("\n.txt files:");
if (txtFiles != null) {
for (File file : txtFiles) {
System.out.println(file.getName());
}
}
}
public static void main(String[] args) {
listDirectory(".");
listDirectory("documents");
}
}
Stream-based I/O
Streams provide a unified way to handle input and output operations
Stream Types
Stream Categories:
- Byte Streams: Handle binary data (8-bit bytes)
- Character Streams: Handle text data (16-bit Unicode)
- Input Streams: Read data from source
- Output Streams: Write data to destination
Byte Streams
- InputStream: Abstract base class
- OutputStream: Abstract base class
- FileInputStream: Read from files
- FileOutputStream: Write to files
- BufferedInputStream: Buffered reading
- BufferedOutputStream: Buffered writing
Character Streams
- Reader: Abstract base class
- Writer: Abstract base class
- FileReader: Read text from files
- FileWriter: Write text to files
- BufferedReader: Buffered text reading
- BufferedWriter: Buffered text writing
Byte Stream Example
Writing Bytes:
import java.io.*;
public class ByteStreamWrite {
public static void main(String[] args) {
String data = "Hello, File I/O!";
// Using FileOutputStream
try (FileOutputStream fos = new FileOutputStream("data.bin")) {
byte[] bytes = data.getBytes();
fos.write(bytes);
System.out.println("Data written to file");
} catch (IOException e) {
System.out.println("Error writing file: " + e.getMessage());
}
// Using BufferedOutputStream for efficiency
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("buffered_data.bin"))) {
for (int i = 0; i < 1000; i++) {
bos.write(("Line " + i + "\n").getBytes());
}
bos.flush(); // Ensure all data is written
System.out.println("Buffered data written");
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Reading Bytes:
public class ByteStreamRead {
public static void main(String[] args) {
// Reading with FileInputStream
try (FileInputStream fis = new FileInputStream("data.bin")) {
int byteData;
System.out.print("File content: ");
while ((byteData = fis.read()) != -1) {
System.out.print((char) byteData);
}
System.out.println();
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
// Reading chunks of data
try (FileInputStream fis = new FileInputStream("data.bin")) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
String content = new String(buffer, 0, bytesRead);
System.out.print(content);
}
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
// Using BufferedInputStream
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("buffered_data.bin"))) {
int data;
int lineCount = 0;
while ((data = bis.read()) != -1) {
if ((char) data == '\n') {
lineCount++;
}
}
System.out.println("Lines read: " + lineCount);
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Character Streams
Character streams are optimized for text data handling
Text File Operations
Writing Text Files:
import java.io.*;
public class TextFileWrite {
public static void main(String[] args) {
// Using FileWriter
try (FileWriter writer = new FileWriter("sample.txt")) {
writer.write("Hello, World!\n");
writer.write("This is a text file.\n");
writer.write("Java File I/O is powerful!");
System.out.println("Text written to file");
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
// Using BufferedWriter for better performance
try (BufferedWriter bufferedWriter = new BufferedWriter(
new FileWriter("large_file.txt"))) {
for (int i = 1; i <= 10000; i++) {
bufferedWriter.write("Line number: " + i);
bufferedWriter.newLine(); // Platform-independent newline
}
System.out.println("Large file written with BufferedWriter");
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
// Using PrintWriter for formatted output
try (PrintWriter printWriter = new PrintWriter("formatted.txt")) {
printWriter.println("Student Report");
printWriter.println("==============");
printWriter.printf("Name: %s%n", "John Doe");
printWriter.printf("Grade: %.2f%n", 87.5);
printWriter.printf("Attendance: %d%%%n", 95);
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Reading Text Files:
public class TextFileRead {
public static void main(String[] args) {
// Using FileReader
try (FileReader reader = new FileReader("sample.txt")) {
int character;
System.out.print("File content: ");
while ((character = reader.read()) != -1) {
System.out.print((char) character);
}
System.out.println();
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
// Using BufferedReader for line-by-line reading
try (BufferedReader bufferedReader = new BufferedReader(
new FileReader("sample.txt"))) {
String line;
int lineNumber = 1;
System.out.println("\nLine by line:");
while ((line = bufferedReader.readLine()) != null) {
System.out.println(lineNumber + ": " + line);
lineNumber++;
}
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
// Reading entire file into a String
try (BufferedReader reader = new BufferedReader(
new FileReader("sample.txt"))) {
StringBuilder content = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
System.out.println("Entire file content:");
System.out.println(content.toString());
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
File Copy Example
import java.io.*;
public class FileCopyExample {
// Copy using byte streams
public static void copyFileBytes(String source, String destination) {
try (FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(destination)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
System.out.println("File copied successfully (byte streams)");
} catch (IOException e) {
System.out.println("Error copying file: " + e.getMessage());
}
}
// Copy using character streams (for text files)
public static void copyFileChars(String source, String destination) {
try (BufferedReader reader = new BufferedReader(new FileReader(source));
BufferedWriter writer = new BufferedWriter(new FileWriter(destination))) {
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine();
}
System.out.println("Text file copied successfully (character streams)");
} catch (IOException e) {
System.out.println("Error copying file: " + e.getMessage());
}
}
// Copy with progress indication
public static void copyFileWithProgress(String source, String destination) {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destination))) {
File sourceFile = new File(source);
long totalBytes = sourceFile.length();
long copiedBytes = 0;
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
copiedBytes += bytesRead;
// Show progress
int progress = (int) ((copiedBytes * 100) / totalBytes);
System.out.print("\rProgress: " + progress + "%");
}
System.out.println("\nFile copied with progress tracking");
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
}
public static void main(String[] args) {
copyFileBytes("source.txt", "destination_bytes.txt");
copyFileChars("source.txt", "destination_chars.txt");
copyFileWithProgress("large_file.txt", "large_file_copy.txt");
}
}
Object Serialization
Serialization converts objects to byte streams for storage or transmission
Serializable Objects
Creating Serializable Class:
import java.io.*;
// Serializable class
class Student implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private double grade;
private transient String password; // Won't be serialized
public Student(String name, int age, double grade, String password) {
this.name = name;
this.age = age;
this.grade = grade;
this.password = password;
}
// Getters and setters
public String getName() { return name; }
public int getAge() { return age; }
public double getGrade() { return grade; }
public String getPassword() { return password; }
@Override
public String toString() {
return "Student{name='" + name + "', age=" + age +
", grade=" + grade + ", password='" + password + "'}";
}
}
// Non-serializable field example
class Course implements Serializable {
private static final long serialVersionUID = 1L;
private String courseName;
private Student[] students;
private static String university = "XYZ University"; // Static fields not serialized
public Course(String courseName, Student[] students) {
this.courseName = courseName;
this.students = students;
}
public String getCourseName() { return courseName; }
public Student[] getStudents() { return students; }
public static String getUniversity() { return university; }
}
Serialization Example:
public class SerializationExample {
// Serialize object to file
public static void serializeStudent(Student student, String filename) {
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(filename))) {
oos.writeObject(student);
System.out.println("Student serialized to " + filename);
} catch (IOException e) {
System.out.println("Serialization error: " + e.getMessage());
}
}
// Deserialize object from file
public static Student deserializeStudent(String filename) {
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(filename))) {
Student student = (Student) ois.readObject();
System.out.println("Student deserialized from " + filename);
return student;
} catch (IOException | ClassNotFoundException e) {
System.out.println("Deserialization error: " + e.getMessage());
return null;
}
}
public static void main(String[] args) {
// Create and serialize student
Student student = new Student("Alice", 20, 85.5, "secret123");
System.out.println("Original: " + student);
serializeStudent(student, "student.ser");
// Deserialize student
Student deserializedStudent = deserializeStudent("student.ser");
if (deserializedStudent != null) {
System.out.println("Deserialized: " + deserializedStudent);
// Note: password will be null (transient field)
}
}
}
Advanced Serialization
Custom Serialization:
class BankAccount implements Serializable {
private static final long serialVersionUID = 1L;
private String accountNumber;
private String holderName;
private transient double balance; // Don't serialize balance directly
public BankAccount(String accountNumber, String holderName, double balance) {
this.accountNumber = accountNumber;
this.holderName = holderName;
this.balance = balance;
}
// Custom serialization method
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject(); // Serialize non-transient fields
// Encrypt balance before serialization
double encryptedBalance = balance * 1.5 + 1000; // Simple encryption
oos.writeDouble(encryptedBalance);
}
// Custom deserialization method
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject(); // Deserialize non-transient fields
// Decrypt balance after deserialization
double encryptedBalance = ois.readDouble();
this.balance = (encryptedBalance - 1000) / 1.5; // Simple decryption
}
public double getBalance() { return balance; }
@Override
public String toString() {
return "BankAccount{accountNumber='" + accountNumber +
"', holderName='" + holderName + "', balance=" + balance + "}";
}
}
Serialization Best Practices:
Do's:
- Always declare serialVersionUID
- Use transient for sensitive data
- Implement custom serialization when needed
- Handle version compatibility
- Close streams properly
Don'ts:
- Don't serialize sensitive information
- Don't serialize large objects unnecessarily
- Don't ignore ClassNotFoundException
- Don't serialize without versioning
Testing Custom Serialization:
public class CustomSerializationTest {
public static void main(String[] args) {
BankAccount account = new BankAccount(
"123456789", "John Doe", 1500.75);
System.out.println("Original: " + account);
// Serialize
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("account.ser"))) {
oos.writeObject(account);
} catch (IOException e) {
e.printStackTrace();
}
// Deserialize
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("account.ser"))) {
BankAccount restoredAccount = (BankAccount) ois.readObject();
System.out.println("Restored: " + restoredAccount);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
File I/O Exception Handling
Proper exception handling is crucial for robust file operations
Common File Exceptions
Exception Types:
- FileNotFoundException: File doesn't exist
- IOException: General I/O error
- SecurityException: Access denied
- OutOfMemoryError: Large file operations
- ClassNotFoundException: Deserialization error
Robust File Operations:
public class SafeFileOperations {
public static String readFileContent(String filename) {
StringBuilder content = new StringBuilder();
try (BufferedReader reader = new BufferedReader(
new FileReader(filename))) {
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
} catch (FileNotFoundException e) {
System.err.println("File not found: " + filename);
return null;
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
return null;
}
return content.toString();
}
public static boolean writeFileContent(String filename, String content) {
try (BufferedWriter writer = new BufferedWriter(
new FileWriter(filename))) {
writer.write(content);
return true;
} catch (IOException e) {
System.err.println("Error writing file: " + e.getMessage());
return false;
}
}
}
Try-with-Resources Best Practice:
public class ResourceManagement {
// Bad practice - manual resource management
public static void badExample(String filename) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(filename));
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// Good practice - try-with-resources
public static void goodExample(String filename) {
try (BufferedReader reader = new BufferedReader(
new FileReader(filename))) {
String line = reader.readLine();
System.out.println(line);
// Reader automatically closed
} catch (IOException e) {
e.printStackTrace();
}
}
// Multiple resources
public static void copyFile(String source, String destination) {
try (BufferedReader reader = new BufferedReader(new FileReader(source));
BufferedWriter writer = new BufferedWriter(new FileWriter(destination))) {
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine();
}
} catch (IOException e) {
System.err.println("Error copying file: " + e.getMessage());
}
}
}
NIO (New I/O) Overview
Java NIO provides more efficient and flexible I/O operations
NIO vs Traditional I/O
| Feature | Traditional I/O | NIO |
|---|---|---|
| Approach | Stream-oriented | Buffer-oriented |
| Blocking | Blocking I/O | Non-blocking I/O |
| Performance | Good for small files | Better for large files |
| Memory Usage | Direct to JVM heap | Direct memory access |
| File Operations | Limited file operations | Rich file operations |
Simple NIO Example:
import java.nio.file.*;
import java.io.IOException;
public class NIOExample {
public static void main(String[] args) {
try {
// Read entire file
Path path = Paths.get("sample.txt");
String content = Files.readString(path);
System.out.println(content);
// Write to file
String data = "Hello NIO!";
Files.writeString(path, data);
// Copy file
Files.copy(path, Paths.get("copy.txt"),
StandardCopyOption.REPLACE_EXISTING);
// Check file properties
System.out.println("File size: " + Files.size(path));
System.out.println("Is readable: " + Files.isReadable(path));
} catch (IOException e) {
e.printStackTrace();
}
}
}
Directory Operations with NIO:
import java.nio.file.*;
import java.io.IOException;
public class NIODirectories {
public static void main(String[] args) {
try {
Path dir = Paths.get("testdir");
// Create directory
Files.createDirectories(dir);
// List directory contents
Files.list(dir).forEach(System.out::println);
// Walk directory tree
Files.walk(dir)
.filter(Files::isRegularFile)
.forEach(System.out::println);
// Find files by pattern
Files.find(dir, 2,
(path, attrs) -> path.toString().endsWith(".txt"))
.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
}
File I/O Best Practices
✅ Best Practices
- Use try-with-resources for automatic cleanup
- Use buffered streams for better performance
- Handle specific exceptions appropriately
- Use character streams for text files
- Use byte streams for binary files
- Check file existence before operations
- Use platform-independent file separators
- Consider NIO for large file operations
⚠️ Common Pitfalls
- Forgetting to close streams
- Not handling FileNotFoundException
- Using wrong stream type for data
- Ignoring character encoding issues
- Not checking file permissions
- Loading entire large files into memory
- Hardcoding file paths
- Not validating user-provided file paths
Chapter Summary
File Operations:
- File and directory manipulation
- Stream-based I/O (byte and character)
- Buffered I/O for performance
- Object serialization
- Exception handling in file operations
Practical Skills:
- Reading and writing files safely
- Copying and moving files
- Serializing objects for persistence
- Using try-with-resources
- Understanding NIO basics
Next: Collections Framework
Thank You!
Questions?
Ready to explore Collections Framework!

