Java File I/O Operations
Java File I/O Operations
File input/output operations are essential for most Java applications. Java provides multiple approaches for file handling, from traditional streams to modern NIO.2 APIs. Understanding these different approaches helps you choose the right tool for each situation.
Prerequisites: This guide assumes familiarity with Java exception handling, streams, and basic OOP concepts. Review Collections Framework for understanding data structures used in examples.
File I/O Evolution in Java
Java has evolved its file handling capabilities over time:
- Java 1.0: Basic FileInputStream/FileOutputStream
- Java 1.1: Character streams with FileReader/FileWriter
- Java 1.4: NIO (New I/O) with channels and buffers
- Java 7: NIO.2 with PathandFilesclasses
- Java 8+: Stream API integration
Basic File Operations with Traditional I/O
Reading Files with Character Streams
 1import java.io.*;
 2import java.util.*;
 3
 4public class TraditionalFileReading {
 5    
 6    public static void readFileWithBufferedReader(String filename) {
 7        System.out.println("=== Reading with BufferedReader ===");
 8        
 9        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
10            String line;
11            int lineNumber = 1;
12            
13            while ((line = reader.readLine()) != null) {
14                System.out.println(lineNumber + ": " + line);
15                lineNumber++;
16            }
17            
18        } catch (FileNotFoundException e) {
19            System.err.println("File not found: " + filename);
20        } catch (IOException e) {
21            System.err.println("Error reading file: " + e.getMessage());
22        }
23    }
24    
25    public static void readFileCharByChar(String filename) {
26        System.out.println("\n=== Reading Character by Character ===");
27        
28        try (FileReader reader = new FileReader(filename)) {
29            int character;
30            int charCount = 0;
31            
32            while ((character = reader.read()) != -1) {
33                char ch = (char) character;
34                System.out.print(ch);
35                charCount++;
36                
37                // Show progress every 100 characters
38                if (charCount % 100 == 0) {
39                    System.out.println("\n[" + charCount + " characters read]");
40                }
41            }
42            
43            System.out.println("\nTotal characters read: " + charCount);
44            
45        } catch (IOException e) {
46            System.err.println("Error reading file: " + e.getMessage());
47        }
48    }
49    
50    public static List<String> readFileToList(String filename) {
51        System.out.println("\n=== Reading File to List ===");
52        
53        List<String> lines = new ArrayList<>();
54        
55        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
56            String line;
57            
58            while ((line = reader.readLine()) != null) {
59                lines.add(line);
60            }
61            
62            System.out.println("Read " + lines.size() + " lines from file");
63            
64        } catch (IOException e) {
65            System.err.println("Error reading file: " + e.getMessage());
66        }
67        
68        return lines;
69    }
70    
71    public static void demonstrateReading() {
72        String filename = "sample.txt";
73        
74        // Create a sample file first
75        createSampleFile(filename);
76        
77        // Demonstrate different reading methods
78        readFileWithBufferedReader(filename);
79        readFileToList(filename);
80    }
81    
82    private static void createSampleFile(String filename) {
83        try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
84            writer.println("This is line 1");
85            writer.println("This is line 2 with some longer content");
86            writer.println("Line 3 contains numbers: 123, 456, 789");
87            writer.println("Line 4 has special characters: @#$%^&*()");
88            writer.println("Final line with mixed content: Hello World! 2024");
89        } catch (IOException e) {
90            System.err.println("Error creating sample file: " + e.getMessage());
91        }
92    }
93}Writing Files with Character Streams
  1import java.io.*;
  2import java.util.*;
  3import java.time.LocalDateTime;
  4import java.time.format.DateTimeFormatter;
  5
  6public class TraditionalFileWriting {
  7    
  8    public static void writeWithPrintWriter(String filename, List<String> data) {
  9        System.out.println("=== Writing with PrintWriter ===");
 10        
 11        try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
 12            
 13            // Write header with timestamp
 14            writer.println("# File generated on: " + LocalDateTime.now());
 15            writer.println("# Total entries: " + data.size());
 16            writer.println("=" * 40);
 17            
 18            // Write data with line numbers
 19            for (int i = 0; i < data.size(); i++) {
 20                writer.printf("%d: %s%n", i + 1, data.get(i));
 21            }
 22            
 23            writer.println("=" * 40);
 24            writer.println("# End of file");
 25            
 26            System.out.println("Successfully wrote " + data.size() + " entries to " + filename);
 27            
 28        } catch (IOException e) {
 29            System.err.println("Error writing file: " + e.getMessage());
 30        }
 31    }
 32    
 33    public static void appendToFile(String filename, String content) {
 34        System.out.println("\n=== Appending to File ===");
 35        
 36        try (PrintWriter writer = new PrintWriter(new FileWriter(filename, true))) {
 37            writer.println();
 38            writer.println("# Appended on: " + LocalDateTime.now());
 39            writer.println(content);
 40            
 41            System.out.println("Successfully appended content to " + filename);
 42            
 43        } catch (IOException e) {
 44            System.err.println("Error appending to file: " + e.getMessage());
 45        }
 46    }
 47    
 48    public static void writeFormattedData(String filename) {
 49        System.out.println("\n=== Writing Formatted Data ===");
 50        
 51        // Sample data
 52        List<Student> students = Arrays.asList(
 53            new Student("Alice Johnson", 123, 3.85),
 54            new Student("Bob Smith", 456, 3.92),
 55            new Student("Charlie Brown", 789, 3.67),
 56            new Student("Diana Prince", 321, 3.99)
 57        );
 58        
 59        try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
 60            
 61            // Write CSV header
 62            writer.println("Name,ID,GPA");
 63            
 64            // Write student data
 65            for (Student student : students) {
 66                writer.printf("%s,%d,%.2f%n", 
 67                    student.getName(), 
 68                    student.getId(), 
 69                    student.getGpa()
 70                );
 71            }
 72            
 73            System.out.println("Successfully wrote " + students.size() + " students to CSV file");
 74            
 75        } catch (IOException e) {
 76            System.err.println("Error writing CSV file: " + e.getMessage());
 77        }
 78    }
 79    
 80    public static void writeWithBufferedWriter(String filename, List<String> lines) {
 81        System.out.println("\n=== Writing with BufferedWriter ===");
 82        
 83        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
 84            
 85            for (String line : lines) {
 86                writer.write(line);
 87                writer.newLine();  // Platform-independent line separator
 88            }
 89            
 90            // Explicitly flush to ensure data is written
 91            writer.flush();
 92            
 93            System.out.println("Successfully wrote " + lines.size() + " lines using BufferedWriter");
 94            
 95        } catch (IOException e) {
 96            System.err.println("Error writing with BufferedWriter: " + e.getMessage());
 97        }
 98    }
 99    
100    // Helper class for formatted data example
101    static class Student {
102        private String name;
103        private int id;
104        private double gpa;
105        
106        public Student(String name, int id, double gpa) {
107            this.name = name;
108            this.id = id;
109            this.gpa = gpa;
110        }
111        
112        public String getName() { return name; }
113        public int getId() { return id; }
114        public double getGpa() { return gpa; }
115    }
116    
117    public static void demonstrateWriting() {
118        List<String> sampleData = Arrays.asList(
119            "First line of data",
120            "Second line with more content",
121            "Third line containing special chars: !@#$%",
122            "Fourth line with numbers: 12345",
123            "Last line of the sample data"
124        );
125        
126        writeWithPrintWriter("output1.txt", sampleData);
127        appendToFile("output1.txt", "This content was appended later");
128        writeFormattedData("students.csv");
129        writeWithBufferedWriter("output2.txt", sampleData);
130    }
131}Binary File Operations
Reading and Writing Binary Data
  1import java.io.*;
  2import java.util.Arrays;
  3
  4public class BinaryFileOperations {
  5    
  6    public static void writeBinaryData(String filename) {
  7        System.out.println("=== Writing Binary Data ===");
  8        
  9        try (DataOutputStream dos = new DataOutputStream(
 10                new BufferedOutputStream(new FileOutputStream(filename)))) {
 11            
 12            // Write different data types
 13            dos.writeInt(42);                    // 4 bytes
 14            dos.writeDouble(3.14159);           // 8 bytes
 15            dos.writeBoolean(true);             // 1 byte
 16            dos.writeUTF("Hello, Binary!");     // Variable length string
 17            dos.writeLong(1234567890L);         // 8 bytes
 18            dos.writeFloat(2.718f);             // 4 bytes
 19            
 20            // Write an array
 21            int[] numbers = {1, 2, 3, 4, 5};
 22            dos.writeInt(numbers.length);       // Array length first
 23            for (int num : numbers) {
 24                dos.writeInt(num);
 25            }
 26            
 27            System.out.println("Binary data written successfully");
 28            
 29        } catch (IOException e) {
 30            System.err.println("Error writing binary data: " + e.getMessage());
 31        }
 32    }
 33    
 34    public static void readBinaryData(String filename) {
 35        System.out.println("\n=== Reading Binary Data ===");
 36        
 37        try (DataInputStream dis = new DataInputStream(
 38                new BufferedInputStream(new FileInputStream(filename)))) {
 39            
 40            // Read data in the same order it was written
 41            int intValue = dis.readInt();
 42            double doubleValue = dis.readDouble();
 43            boolean boolValue = dis.readBoolean();
 44            String stringValue = dis.readUTF();
 45            long longValue = dis.readLong();
 46            float floatValue = dis.readFloat();
 47            
 48            // Read the array
 49            int arrayLength = dis.readInt();
 50            int[] numbers = new int[arrayLength];
 51            for (int i = 0; i < arrayLength; i++) {
 52                numbers[i] = dis.readInt();
 53            }
 54            
 55            // Display the read data
 56            System.out.println("Integer: " + intValue);
 57            System.out.println("Double: " + doubleValue);
 58            System.out.println("Boolean: " + boolValue);
 59            System.out.println("String: " + stringValue);
 60            System.out.println("Long: " + longValue);
 61            System.out.println("Float: " + floatValue);
 62            System.out.println("Array: " + Arrays.toString(numbers));
 63            
 64        } catch (IOException e) {
 65            System.err.println("Error reading binary data: " + e.getMessage());
 66        }
 67    }
 68    
 69    public static void copyBinaryFile(String sourceFile, String targetFile) {
 70        System.out.println("\n=== Copying Binary File ===");
 71        
 72        try (InputStream input = new BufferedInputStream(new FileInputStream(sourceFile));
 73             OutputStream output = new BufferedOutputStream(new FileOutputStream(targetFile))) {
 74            
 75            byte[] buffer = new byte[8192];  // 8KB buffer
 76            int bytesRead;
 77            long totalBytes = 0;
 78            
 79            while ((bytesRead = input.read(buffer)) != -1) {
 80                output.write(buffer, 0, bytesRead);
 81                totalBytes += bytesRead;
 82            }
 83            
 84            System.out.println("Copied " + totalBytes + " bytes from " + sourceFile + " to " + targetFile);
 85            
 86        } catch (IOException e) {
 87            System.err.println("Error copying file: " + e.getMessage());
 88        }
 89    }
 90    
 91    public static void demonstrateSerialization() {
 92        System.out.println("\n=== Object Serialization ===");
 93        
 94        // Create a serializable object
 95        SerializableStudent student = new SerializableStudent("John Doe", 12345, 3.75);
 96        student.addGrade("Math", 95);
 97        student.addGrade("Science", 88);
 98        student.addGrade("English", 92);
 99        
100        String filename = "student.ser";
101        
102        // Serialize the object
103        try (ObjectOutputStream oos = new ObjectOutputStream(
104                new FileOutputStream(filename))) {
105            
106            oos.writeObject(student);
107            System.out.println("Student object serialized successfully");
108            
109        } catch (IOException e) {
110            System.err.println("Error serializing object: " + e.getMessage());
111        }
112        
113        // Deserialize the object
114        try (ObjectInputStream ois = new ObjectInputStream(
115                new FileInputStream(filename))) {
116            
117            SerializableStudent deserializedStudent = (SerializableStudent) ois.readObject();
118            System.out.println("Deserialized student: " + deserializedStudent);
119            
120        } catch (IOException | ClassNotFoundException e) {
121            System.err.println("Error deserializing object: " + e.getMessage());
122        }
123    }
124    
125    // Serializable student class
126    static class SerializableStudent implements Serializable {
127        private static final long serialVersionUID = 1L;
128        
129        private String name;
130        private int id;
131        private double gpa;
132        private Map<String, Integer> grades;
133        
134        public SerializableStudent(String name, int id, double gpa) {
135            this.name = name;
136            this.id = id;
137            this.gpa = gpa;
138            this.grades = new HashMap<>();
139        }
140        
141        public void addGrade(String subject, int grade) {
142            grades.put(subject, grade);
143        }
144        
145        @Override
146        public String toString() {
147            return String.format("Student{name='%s', id=%d, gpa=%.2f, grades=%s}", 
148                               name, id, gpa, grades);
149        }
150    }
151    
152    public static void demonstrateBinaryOperations() {
153        String binaryFile = "data.bin";
154        
155        writeBinaryData(binaryFile);
156        readBinaryData(binaryFile);
157        copyBinaryFile(binaryFile, "data_copy.bin");
158        demonstrateSerialization();
159    }
160}Modern Java NIO.2 (Path and Files)
Working with Paths and Files
  1import java.nio.file.*;
  2import java.nio.charset.StandardCharsets;
  3import java.io.IOException;
  4import java.util.List;
  5import java.util.stream.Stream;
  6
  7public class ModernFileOperations {
  8    
  9    public static void demonstratePathOperations() {
 10        System.out.println("=== Path Operations ===");
 11        
 12        // Creating paths
 13        Path currentDir = Paths.get(".");
 14        Path absolutePath = currentDir.toAbsolutePath();
 15        Path normalizedPath = absolutePath.normalize();
 16        
 17        System.out.println("Current directory: " + currentDir);
 18        System.out.println("Absolute path: " + absolutePath);
 19        System.out.println("Normalized path: " + normalizedPath);
 20        
 21        // Path components
 22        Path filePath = Paths.get("/home/user/documents/file.txt");
 23        System.out.println("\nPath analysis for: " + filePath);
 24        System.out.println("Parent: " + filePath.getParent());
 25        System.out.println("Filename: " + filePath.getFileName());
 26        System.out.println("Root: " + filePath.getRoot());
 27        System.out.println("Name count: " + filePath.getNameCount());
 28        
 29        // Resolving paths
 30        Path baseDir = Paths.get("/home/user");
 31        Path resolvedPath = baseDir.resolve("documents/file.txt");
 32        System.out.println("Resolved path: " + resolvedPath);
 33        
 34        // Relativizing paths
 35        Path path1 = Paths.get("/home/user/documents");
 36        Path path2 = Paths.get("/home/user/pictures");
 37        Path relativePath = path1.relativize(path2);
 38        System.out.println("Relative path from documents to pictures: " + relativePath);
 39    }
 40    
 41    public static void readFileWithNIO(String filename) {
 42        System.out.println("\n=== Reading with NIO.2 ===");
 43        
 44        Path filePath = Paths.get(filename);
 45        
 46        try {
 47            // Read entire file as string
 48            String content = Files.readString(filePath, StandardCharsets.UTF_8);
 49            System.out.println("File content:\n" + content);
 50            
 51            // Read all lines into a list
 52            List<String> lines = Files.readAllLines(filePath, StandardCharsets.UTF_8);
 53            System.out.println("\nFile has " + lines.size() + " lines");
 54            
 55            // Read lines as a stream (memory efficient for large files)
 56            System.out.println("\nProcessing lines with stream:");
 57            try (Stream<String> lineStream = Files.lines(filePath)) {
 58                lineStream
 59                    .filter(line -> line.contains("line"))
 60                    .map(String::toUpperCase)
 61                    .forEach(System.out::println);
 62            }
 63            
 64        } catch (IOException e) {
 65            System.err.println("Error reading file: " + e.getMessage());
 66        }
 67    }
 68    
 69    public static void writeFileWithNIO(String filename, List<String> data) {
 70        System.out.println("\n=== Writing with NIO.2 ===");
 71        
 72        Path filePath = Paths.get(filename);
 73        
 74        try {
 75            // Write all lines at once
 76            Files.write(filePath, data, StandardCharsets.UTF_8);
 77            System.out.println("Successfully wrote " + data.size() + " lines to " + filename);
 78            
 79            // Append additional content
 80            String additionalContent = "\nAppended with NIO.2";
 81            Files.write(filePath, additionalContent.getBytes(StandardCharsets.UTF_8), 
 82                       StandardOpenOption.APPEND);
 83            
 84            System.out.println("Appended additional content");
 85            
 86        } catch (IOException e) {
 87            System.err.println("Error writing file: " + e.getMessage());
 88        }
 89    }
 90    
 91    public static void fileMetadataOperations() {
 92        System.out.println("\n=== File Metadata Operations ===");
 93        
 94        Path filePath = Paths.get("sample.txt");
 95        
 96        try {
 97            // Check file existence and properties
 98            boolean exists = Files.exists(filePath);
 99            boolean isRegularFile = Files.isRegularFile(filePath);
100            boolean isDirectory = Files.isDirectory(filePath);
101            boolean isReadable = Files.isReadable(filePath);
102            boolean isWritable = Files.isWritable(filePath);
103            boolean isExecutable = Files.isExecutable(filePath);
104            
105            System.out.println("File: " + filePath);
106            System.out.println("Exists: " + exists);
107            System.out.println("Is regular file: " + isRegularFile);
108            System.out.println("Is directory: " + isDirectory);
109            System.out.println("Is readable: " + isReadable);
110            System.out.println("Is writable: " + isWritable);
111            System.out.println("Is executable: " + isExecutable);
112            
113            if (exists) {
114                // Get file attributes
115                long size = Files.size(filePath);
116                System.out.println("File size: " + size + " bytes");
117                
118                // Get file times
119                BasicFileAttributes attrs = Files.readAttributes(filePath, BasicFileAttributes.class);
120                System.out.println("Creation time: " + attrs.creationTime());
121                System.out.println("Last modified: " + attrs.lastModifiedTime());
122                System.out.println("Last accessed: " + attrs.lastAccessTime());
123            }
124            
125        } catch (IOException e) {
126            System.err.println("Error reading file metadata: " + e.getMessage());
127        }
128    }
129    
130    public static void directoryOperations() {
131        System.out.println("\n=== Directory Operations ===");
132        
133        Path currentDir = Paths.get(".");
134        
135        try {
136            // List directory contents
137            System.out.println("Directory contents:");
138            try (Stream<Path> paths = Files.list(currentDir)) {
139                paths.filter(Files::isRegularFile)
140                     .forEach(path -> {
141                         try {
142                             long size = Files.size(path);
143                             System.out.println(path.getFileName() + " (" + size + " bytes)");
144                         } catch (IOException e) {
145                             System.out.println(path.getFileName() + " (size unknown)");
146                         }
147                     });
148            }
149            
150            // Walk directory tree
151            System.out.println("\nWalking directory tree (max depth 2):");
152            try (Stream<Path> paths = Files.walk(currentDir, 2)) {
153                paths.filter(Files::isRegularFile)
154                     .filter(path -> path.toString().endsWith(".txt"))
155                     .forEach(System.out::println);
156            }
157            
158            // Create directories
159            Path newDir = Paths.get("test_directory");
160            if (!Files.exists(newDir)) {
161                Files.createDirectory(newDir);
162                System.out.println("Created directory: " + newDir);
163                
164                // Create a file in the new directory
165                Path newFile = newDir.resolve("test_file.txt");
166                Files.write(newFile, "This is a test file".getBytes());
167                System.out.println("Created file: " + newFile);
168            }
169            
170        } catch (IOException e) {
171            System.err.println("Error in directory operations: " + e.getMessage());
172        }
173    }
174    
175    public static void fileCopyMoveOperations() {
176        System.out.println("\n=== File Copy and Move Operations ===");
177        
178        try {
179            // Create source file
180            Path sourceFile = Paths.get("source.txt");
181            Files.write(sourceFile, "This is the source file content".getBytes());
182            
183            // Copy file
184            Path copyFile = Paths.get("copy.txt");
185            Files.copy(sourceFile, copyFile, StandardCopyOption.REPLACE_EXISTING);
186            System.out.println("Copied " + sourceFile + " to " + copyFile);
187            
188            // Move file
189            Path movedFile = Paths.get("moved.txt");
190            Files.move(copyFile, movedFile, StandardCopyOption.REPLACE_EXISTING);
191            System.out.println("Moved " + copyFile + " to " + movedFile);
192            
193            // Delete file
194            Files.delete(movedFile);
195            System.out.println("Deleted " + movedFile);
196            
197            // Safe delete (doesn't throw exception if file doesn't exist)
198            boolean deleted = Files.deleteIfExists(sourceFile);
199            System.out.println("Source file deleted: " + deleted);
200            
201        } catch (IOException e) {
202            System.err.println("Error in file operations: " + e.getMessage());
203        }
204    }
205    
206    public static void demonstrateNIOOperations() {
207        // Create sample data
208        List<String> sampleData = Arrays.asList(
209            "Line 1: Introduction to NIO.2",
210            "Line 2: Path operations are powerful",
211            "Line 3: Files class provides many utilities",
212            "Line 4: Stream integration is excellent",
213            "Line 5: Modern Java file handling"
214        );
215        
216        demonstratePathOperations();
217        writeFileWithNIO("nio_sample.txt", sampleData);
218        readFileWithNIO("nio_sample.txt");
219        fileMetadataOperations();
220        directoryOperations();
221        fileCopyMoveOperations();
222    }
223}Working with Different File Formats
CSV File Processing
  1import java.io.*;
  2import java.util.*;
  3import java.util.stream.Collectors;
  4
  5public class CSVFileProcessor {
  6    
  7    static class Employee {
  8        private String name;
  9        private String department;
 10        private double salary;
 11        private int experience;
 12        
 13        public Employee(String name, String department, double salary, int experience) {
 14            this.name = name;
 15            this.department = department;
 16            this.salary = salary;
 17            this.experience = experience;
 18        }
 19        
 20        // Getters
 21        public String getName() { return name; }
 22        public String getDepartment() { return department; }
 23        public double getSalary() { return salary; }
 24        public int getExperience() { return experience; }
 25        
 26        @Override
 27        public String toString() {
 28            return String.format("Employee{name='%s', dept='%s', salary=%.2f, exp=%d}", 
 29                               name, department, salary, experience);
 30        }
 31        
 32        public String toCSV() {
 33            return String.format("%s,%s,%.2f,%d", name, department, salary, experience);
 34        }
 35        
 36        public static Employee fromCSV(String csvLine) {
 37            String[] parts = csvLine.split(",");
 38            return new Employee(
 39                parts[0].trim(),
 40                parts[1].trim(),
 41                Double.parseDouble(parts[2].trim()),
 42                Integer.parseInt(parts[3].trim())
 43            );
 44        }
 45    }
 46    
 47    public static void writeEmployeesToCSV(String filename, List<Employee> employees) {
 48        System.out.println("=== Writing Employees to CSV ===");
 49        
 50        try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
 51            // Write header
 52            writer.println("Name,Department,Salary,Experience");
 53            
 54            // Write employee data
 55            for (Employee emp : employees) {
 56                writer.println(emp.toCSV());
 57            }
 58            
 59            System.out.println("Successfully wrote " + employees.size() + " employees to " + filename);
 60            
 61        } catch (IOException e) {
 62            System.err.println("Error writing CSV file: " + e.getMessage());
 63        }
 64    }
 65    
 66    public static List<Employee> readEmployeesFromCSV(String filename) {
 67        System.out.println("\n=== Reading Employees from CSV ===");
 68        
 69        List<Employee> employees = new ArrayList<>();
 70        
 71        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
 72            String line = reader.readLine(); // Skip header
 73            
 74            while ((line = reader.readLine()) != null) {
 75                if (!line.trim().isEmpty()) {
 76                    try {
 77                        Employee emp = Employee.fromCSV(line);
 78                        employees.add(emp);
 79                    } catch (Exception e) {
 80                        System.err.println("Error parsing line: " + line + " - " + e.getMessage());
 81                    }
 82                }
 83            }
 84            
 85            System.out.println("Successfully read " + employees.size() + " employees from " + filename);
 86            
 87        } catch (IOException e) {
 88            System.err.println("Error reading CSV file: " + e.getMessage());
 89        }
 90        
 91        return employees;
 92    }
 93    
 94    public static void analyzeEmployeeData(List<Employee> employees) {
 95        System.out.println("\n=== Employee Data Analysis ===");
 96        
 97        // Group by department
 98        Map<String, List<Employee>> byDepartment = employees.stream()
 99            .collect(Collectors.groupingBy(Employee::getDepartment));
100        
101        System.out.println("Employees by department:");
102        byDepartment.forEach((dept, empList) -> {
103            double avgSalary = empList.stream()
104                .mapToDouble(Employee::getSalary)
105                .average()
106                .orElse(0.0);
107            
108            System.out.printf("%s: %d employees, avg salary: $%.2f%n", 
109                            dept, empList.size(), avgSalary);
110        });
111        
112        // Find highest paid employee
113        Employee highestPaid = employees.stream()
114            .max(Comparator.comparingDouble(Employee::getSalary))
115            .orElse(null);
116        
117        if (highestPaid != null) {
118            System.out.println("Highest paid: " + highestPaid);
119        }
120        
121        // Calculate overall statistics
122        DoubleSummaryStatistics salaryStats = employees.stream()
123            .mapToDouble(Employee::getSalary)
124            .summaryStatistics();
125        
126        System.out.printf("Salary statistics: min=%.2f, max=%.2f, avg=%.2f%n",
127                         salaryStats.getMin(), salaryStats.getMax(), salaryStats.getAverage());
128    }
129    
130    public static void demonstrateCSVProcessing() {
131        List<Employee> employees = Arrays.asList(
132            new Employee("Alice Johnson", "Engineering", 95000, 5),
133            new Employee("Bob Smith", "Marketing", 67000, 3),
134            new Employee("Charlie Brown", "Engineering", 78000, 2),
135            new Employee("Diana Prince", "Sales", 82000, 4),
136            new Employee("Eve Wilson", "Engineering", 89000, 6),
137            new Employee("Frank Miller", "Marketing", 71000, 4),
138            new Employee("Grace Lee", "Sales", 76000, 3)
139        );
140        
141        String csvFile = "employees.csv";
142        
143        writeEmployeesToCSV(csvFile, employees);
144        List<Employee> readEmployees = readEmployeesFromCSV(csvFile);
145        analyzeEmployeeData(readEmployees);
146    }
147}Properties File Handling
  1import java.io.*;
  2import java.util.Properties;
  3import java.util.Enumeration;
  4
  5public class PropertiesFileHandler {
  6    
  7    public static void createConfigurationFile(String filename) {
  8        System.out.println("=== Creating Configuration File ===");
  9        
 10        Properties config = new Properties();
 11        
 12        // Database configuration
 13        config.setProperty("db.host", "localhost");
 14        config.setProperty("db.port", "5432");
 15        config.setProperty("db.name", "myapp");
 16        config.setProperty("db.username", "admin");
 17        config.setProperty("db.password", "secret123");
 18        
 19        // Application settings
 20        config.setProperty("app.name", "My Application");
 21        config.setProperty("app.version", "1.2.3");
 22        config.setProperty("app.debug", "true");
 23        config.setProperty("app.max.connections", "100");
 24        
 25        // Server configuration
 26        config.setProperty("server.port", "8080");
 27        config.setProperty("server.timeout", "30000");
 28        
 29        try (FileOutputStream output = new FileOutputStream(filename)) {
 30            config.store(output, "Application Configuration");
 31            System.out.println("Configuration saved to " + filename);
 32            
 33        } catch (IOException e) {
 34            System.err.println("Error saving configuration: " + e.getMessage());
 35        }
 36    }
 37    
 38    public static Properties loadConfigurationFile(String filename) {
 39        System.out.println("\n=== Loading Configuration File ===");
 40        
 41        Properties config = new Properties();
 42        
 43        try (FileInputStream input = new FileInputStream(filename)) {
 44            config.load(input);
 45            System.out.println("Configuration loaded from " + filename);
 46            
 47            // Display loaded properties
 48            System.out.println("Loaded " + config.size() + " properties:");
 49            Enumeration<Object> keys = config.keys();
 50            while (keys.hasMoreElements()) {
 51                String key = (String) keys.nextElement();
 52                String value = config.getProperty(key);
 53                System.out.println("  " + key + " = " + value);
 54            }
 55            
 56        } catch (IOException e) {
 57            System.err.println("Error loading configuration: " + e.getMessage());
 58        }
 59        
 60        return config;
 61    }
 62    
 63    public static void updateConfiguration(String filename, String key, String value) {
 64        System.out.println("\n=== Updating Configuration ===");
 65        
 66        Properties config = new Properties();
 67        
 68        // Load existing properties
 69        try (FileInputStream input = new FileInputStream(filename)) {
 70            config.load(input);
 71        } catch (IOException e) {
 72            System.err.println("Error loading existing configuration: " + e.getMessage());
 73            return;
 74        }
 75        
 76        // Update property
 77        String oldValue = config.getProperty(key);
 78        config.setProperty(key, value);
 79        
 80        // Save updated properties
 81        try (FileOutputStream output = new FileOutputStream(filename)) {
 82            config.store(output, "Updated Configuration");
 83            System.out.println("Updated " + key + ": " + oldValue + " -> " + value);
 84            
 85        } catch (IOException e) {
 86            System.err.println("Error saving updated configuration: " + e.getMessage());
 87        }
 88    }
 89    
 90    public static void demonstrateTypedPropertyAccess(Properties config) {
 91        System.out.println("\n=== Typed Property Access ===");
 92        
 93        // String properties
 94        String appName = config.getProperty("app.name", "Unknown Application");
 95        String dbHost = config.getProperty("db.host", "localhost");
 96        
 97        // Integer properties
 98        int serverPort = Integer.parseInt(config.getProperty("server.port", "8080"));
 99        int maxConnections = Integer.parseInt(config.getProperty("app.max.connections", "50"));
100        
101        // Boolean properties
102        boolean debugMode = Boolean.parseBoolean(config.getProperty("app.debug", "false"));
103        
104        // Long properties
105        long timeout = Long.parseLong(config.getProperty("server.timeout", "30000"));
106        
107        System.out.println("Application: " + appName);
108        System.out.println("Database Host: " + dbHost);
109        System.out.println("Server Port: " + serverPort);
110        System.out.println("Max Connections: " + maxConnections);
111        System.out.println("Debug Mode: " + debugMode);
112        System.out.println("Timeout: " + timeout + "ms");
113        
114        // Validate configuration
115        if (serverPort < 1024 || serverPort > 65535) {
116            System.err.println("Warning: Invalid server port " + serverPort);
117        }
118        
119        if (maxConnections <= 0) {
120            System.err.println("Warning: Invalid max connections " + maxConnections);
121        }
122    }
123    
124    public static void demonstratePropertiesHandling() {
125        String configFile = "app.properties";
126        
127        createConfigurationFile(configFile);
128        Properties config = loadConfigurationFile(configFile);
129        updateConfiguration(configFile, "app.version", "1.3.0");
130        
131        // Reload to see changes
132        config = loadConfigurationFile(configFile);
133        demonstrateTypedPropertyAccess(config);
134    }
135}Performance Considerations and Best Practices
Buffered vs Unbuffered I/O
  1import java.io.*;
  2import java.nio.file.*;
  3import java.util.ArrayList;
  4import java.util.List;
  5
  6public class FileIOPerformance {
  7    
  8    public static void compareReadPerformance(String filename, int iterations) {
  9        System.out.println("=== Read Performance Comparison ===");
 10        
 11        // Create test file
 12        createTestFile(filename, 10000);
 13        
 14        // Test unbuffered reading
 15        long startTime = System.nanoTime();
 16        for (int i = 0; i < iterations; i++) {
 17            readFileUnbuffered(filename);
 18        }
 19        long unbufferedTime = System.nanoTime() - startTime;
 20        
 21        // Test buffered reading
 22        startTime = System.nanoTime();
 23        for (int i = 0; i < iterations; i++) {
 24            readFileBuffered(filename);
 25        }
 26        long bufferedTime = System.nanoTime() - startTime;
 27        
 28        // Test NIO.2 reading
 29        startTime = System.nanoTime();
 30        for (int i = 0; i < iterations; i++) {
 31            readFileNIO(filename);
 32        }
 33        long nioTime = System.nanoTime() - startTime;
 34        
 35        System.out.printf("Unbuffered reading (%d iterations): %d ms%n", 
 36                         iterations, unbufferedTime / 1_000_000);
 37        System.out.printf("Buffered reading (%d iterations): %d ms%n", 
 38                         iterations, bufferedTime / 1_000_000);
 39        System.out.printf("NIO.2 reading (%d iterations): %d ms%n", 
 40                         iterations, nioTime / 1_000_000);
 41        
 42        double bufferedSpeedup = (double) unbufferedTime / bufferedTime;
 43        double nioSpeedup = (double) unbufferedTime / nioTime;
 44        
 45        System.out.printf("Buffered is %.2fx faster than unbuffered%n", bufferedSpeedup);
 46        System.out.printf("NIO.2 is %.2fx faster than unbuffered%n", nioSpeedup);
 47    }
 48    
 49    private static void createTestFile(String filename, int lines) {
 50        try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
 51            for (int i = 1; i <= lines; i++) {
 52                writer.println("This is line " + i + " with some content to make it longer");
 53            }
 54        } catch (IOException e) {
 55            System.err.println("Error creating test file: " + e.getMessage());
 56        }
 57    }
 58    
 59    private static List<String> readFileUnbuffered(String filename) {
 60        List<String> lines = new ArrayList<>();
 61        try (FileReader reader = new FileReader(filename)) {
 62            StringBuilder line = new StringBuilder();
 63            int character;
 64            
 65            while ((character = reader.read()) != -1) {
 66                if (character == '\n') {
 67                    lines.add(line.toString());
 68                    line = new StringBuilder();
 69                } else {
 70                    line.append((char) character);
 71                }
 72            }
 73            
 74            if (line.length() > 0) {
 75                lines.add(line.toString());
 76            }
 77            
 78        } catch (IOException e) {
 79            System.err.println("Error reading file: " + e.getMessage());
 80        }
 81        return lines;
 82    }
 83    
 84    private static List<String> readFileBuffered(String filename) {
 85        List<String> lines = new ArrayList<>();
 86        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
 87            String line;
 88            while ((line = reader.readLine()) != null) {
 89                lines.add(line);
 90            }
 91        } catch (IOException e) {
 92            System.err.println("Error reading file: " + e.getMessage());
 93        }
 94        return lines;
 95    }
 96    
 97    private static List<String> readFileNIO(String filename) {
 98        try {
 99            return Files.readAllLines(Paths.get(filename));
100        } catch (IOException e) {
101            System.err.println("Error reading file: " + e.getMessage());
102            return new ArrayList<>();
103        }
104    }
105    
106    public static void demonstrateBufferSizeImpact() {
107        System.out.println("\n=== Buffer Size Impact ===");
108        
109        String filename = "large_test.txt";
110        createTestFile(filename, 50000);
111        
112        int[] bufferSizes = {1024, 4096, 8192, 16384, 32768};
113        
114        for (int bufferSize : bufferSizes) {
115            long startTime = System.nanoTime();
116            copyFileWithBuffer(filename, "copy_" + bufferSize + ".txt", bufferSize);
117            long endTime = System.nanoTime();
118            
119            System.out.printf("Buffer size %d bytes: %d ms%n", 
120                             bufferSize, (endTime - startTime) / 1_000_000);
121        }
122    }
123    
124    private static void copyFileWithBuffer(String source, String target, int bufferSize) {
125        try (InputStream input = new FileInputStream(source);
126             OutputStream output = new FileOutputStream(target)) {
127            
128            byte[] buffer = new byte[bufferSize];
129            int bytesRead;
130            
131            while ((bytesRead = input.read(buffer)) != -1) {
132                output.write(buffer, 0, bytesRead);
133            }
134            
135        } catch (IOException e) {
136            System.err.println("Error copying file: " + e.getMessage());
137        }
138    }
139    
140    public static void demonstratePerformanceTesting() {
141        compareReadPerformance("test_performance.txt", 100);
142        demonstrateBufferSizeImpact();
143    }
144}Error Handling and Resource Management
Comprehensive Error Handling
  1import java.io.*;
  2import java.nio.file.*;
  3import java.util.List;
  4
  5public class FileErrorHandling {
  6    
  7    public static void robustFileReading(String filename) {
  8        System.out.println("=== Robust File Reading ===");
  9        
 10        Path filePath = Paths.get(filename);
 11        
 12        // Check file existence and permissions before attempting to read
 13        if (!Files.exists(filePath)) {
 14            System.err.println("File does not exist: " + filename);
 15            return;
 16        }
 17        
 18        if (!Files.isReadable(filePath)) {
 19            System.err.println("File is not readable: " + filename);
 20            return;
 21        }
 22        
 23        if (Files.isDirectory(filePath)) {
 24            System.err.println("Path is a directory, not a file: " + filename);
 25            return;
 26        }
 27        
 28        try {
 29            long fileSize = Files.size(filePath);
 30            System.out.println("Reading file: " + filename + " (size: " + fileSize + " bytes)");
 31            
 32            List<String> lines = Files.readAllLines(filePath);
 33            System.out.println("Successfully read " + lines.size() + " lines");
 34            
 35            // Process lines safely
 36            for (int i = 0; i < Math.min(5, lines.size()); i++) {
 37                System.out.println("Line " + (i + 1) + ": " + lines.get(i));
 38            }
 39            
 40        } catch (IOException e) {
 41            System.err.println("I/O error reading file: " + e.getMessage());
 42        } catch (OutOfMemoryError e) {
 43            System.err.println("File too large to read into memory: " + e.getMessage());
 44        } catch (SecurityException e) {
 45            System.err.println("Security error accessing file: " + e.getMessage());
 46        }
 47    }
 48    
 49    public static void safeFileWriting(String filename, List<String> data) {
 50        System.out.println("\n=== Safe File Writing ===");
 51        
 52        Path filePath = Paths.get(filename);
 53        Path parentDir = filePath.getParent();
 54        
 55        try {
 56            // Ensure parent directory exists
 57            if (parentDir != null && !Files.exists(parentDir)) {
 58                Files.createDirectories(parentDir);
 59                System.out.println("Created directory: " + parentDir);
 60            }
 61            
 62            // Check if we can write to the location
 63            if (Files.exists(filePath) && !Files.isWritable(filePath)) {
 64                System.err.println("File exists but is not writable: " + filename);
 65                return;
 66            }
 67            
 68            // Create backup if file exists
 69            Path backupPath = null;
 70            if (Files.exists(filePath)) {
 71                backupPath = Paths.get(filename + ".backup");
 72                Files.copy(filePath, backupPath, StandardCopyOption.REPLACE_EXISTING);
 73                System.out.println("Created backup: " + backupPath);
 74            }
 75            
 76            // Write to temporary file first
 77            Path tempPath = Paths.get(filename + ".tmp");
 78            
 79            try {
 80                Files.write(tempPath, data);
 81                
 82                // Atomic move to final location
 83                Files.move(tempPath, filePath, StandardCopyOption.REPLACE_EXISTING);
 84                System.out.println("Successfully wrote " + data.size() + " lines to " + filename);
 85                
 86                // Remove backup on success
 87                if (backupPath != null) {
 88                    Files.deleteIfExists(backupPath);
 89                }
 90                
 91            } catch (IOException e) {
 92                // Restore backup on failure
 93                if (backupPath != null && Files.exists(backupPath)) {
 94                    Files.move(backupPath, filePath, StandardCopyOption.REPLACE_EXISTING);
 95                    System.err.println("Write failed, restored backup");
 96                }
 97                
 98                // Clean up temporary file
 99                Files.deleteIfExists(tempPath);
100                throw e;
101            }
102            
103        } catch (IOException e) {
104            System.err.println("Error writing file: " + e.getMessage());
105        } catch (SecurityException e) {
106            System.err.println("Security error writing file: " + e.getMessage());
107        }
108    }
109    
110    public static void demonstrateResourceManagement() {
111        System.out.println("\n=== Resource Management ===");
112        
113        // Try-with-resources with multiple resources
114        String inputFile = "input.txt";
115        String outputFile = "output.txt";
116        
117        // Create sample input file
118        try {
119            Files.write(Paths.get(inputFile), "Sample content for processing".getBytes());
120        } catch (IOException e) {
121            System.err.println("Error creating input file: " + e.getMessage());
122            return;
123        }
124        
125        // Process file with proper resource management
126        try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputFile));
127             BufferedWriter writer = Files.newBufferedWriter(Paths.get(outputFile))) {
128            
129            String line;
130            int lineNumber = 1;
131            
132            while ((line = reader.readLine()) != null) {
133                // Process line
134                String processedLine = String.format("[%d] %s (processed)", lineNumber, line.toUpperCase());
135                writer.write(processedLine);
136                writer.newLine();
137                lineNumber++;
138            }
139            
140            System.out.println("File processing completed successfully");
141            
142        } catch (IOException e) {
143            System.err.println("Error processing file: " + e.getMessage());
144            
145            // Clean up output file on error
146            try {
147                Files.deleteIfExists(Paths.get(outputFile));
148            } catch (IOException cleanupError) {
149                System.err.println("Error cleaning up output file: " + cleanupError.getMessage());
150            }
151        }
152    }
153    
154    public static void demonstrateErrorHandling() {
155        // Test with non-existent file
156        robustFileReading("non_existent_file.txt");
157        
158        // Create sample data for writing
159        List<String> sampleData = Arrays.asList(
160            "Line 1: Sample data",
161            "Line 2: More content",
162            "Line 3: Final line"
163        );
164        
165        // Test safe file writing
166        safeFileWriting("test_output.txt", sampleData);
167        
168        // Test successful reading
169        robustFileReading("test_output.txt");
170        
171        demonstrateResourceManagement();
172    }
173}Best Practices Summary
File I/O Best Practices:
- Use try-with-resources for automatic resource management
- Choose appropriate I/O method:- Use NIO.2 (Filesclass) for simple operations
- Use buffered streams for large files
- Use binary streams for non-text data
 
- Use NIO.2 (
- Handle exceptions appropriately - distinguish between different error types
- Validate inputs - check file existence, permissions, and sizes
- Use proper encoding - specify charset explicitly (UTF-8 recommended)
- Consider memory usage - use streaming for large files
- Implement atomic operations - write to temp file then move
- Create backups for critical file modifications
Common Pitfalls:
- Not closing resources properly (use try-with-resources)
- Ignoring character encoding (causes corruption)
- Reading entire large files into memory (use streaming)
- Not handling IOException properly
- Platform-dependent path separators (use PathAPI)
- Not checking file permissions before operations
- Modifying files in-place without backups
Java’s file I/O capabilities have evolved significantly, providing developers with powerful, flexible tools for handling files efficiently and safely. Choose the right approach based on your specific requirements and always implement proper error handling and resource management.
← Previous: Collections Framework Next: Threads & Concurrency →