Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
92: File I/O with java.io
Wait, there are so many classes—FileReader, BufferedReader, FileInputStream... which one do I actually use?
It's a bit of a mess, right? The java.io package has been around since the early days, and it shows. The most important thing to understand is the difference between byte streams and character streams.
If you're dealing with images, PDFs, or zipped files, you want byte streams (the ones ending in InputStream or OutputStream). But since you're likely working with text files, you want character streams. I almost always wrap a FileReader inside a BufferedReader. Why? Because FileReader reads one character at a time, which is incredibly slow. BufferedReader reads a large chunk of the file into memory at once, allowing you to use the readLine() method.
// Reading a simple config file
try (BufferedReader reader = new BufferedReader(new FileReader("config.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println("Loaded setting: " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
Do I really need that weird try-with-resources syntax, or can I just call .close() at the end?
Trust me on this: use the try-with-resources block. In the old days, we'd put file.close() in a finally block. But here's the catch: if an exception happens while reading the file, and then another exception happens while closing the file, the second one can "swallow" the first one, leaving you with a bug that's nearly impossible to trace.
By putting the resource inside the try (...) parentheses, Java guarantees that the file is closed the moment the block exits, regardless of whether it finished successfully or crashed. It's cleaner, and it prevents "file handle leaks" that can eventually crash your application or lock the file so other programs can't touch it.
How do I add new lines to a file instead of wiping the whole thing every time I save?
By default, when you create a FileWriter, it starts at the beginning of the file and overwrites everything. If you're building something like a log file, that's a disaster. To fix this, you need to use the constructor that takes a second boolean argument: append.
Setting this to true tells Java to jump to the end of the file before it starts writing. I usually pair this with a PrintWriter because it gives you println(), which handles the line breaks for you automatically across different operating systems.
// Appending a log entry to a file
String logEntry = "User logged in at " + java.time.LocalDateTime.now();
try (FileWriter fw = new FileWriter("app.log", true);
PrintWriter out = new PrintWriter(fw)) {
out.println(logEntry);
} catch (IOException e) {
System.err.println("Couldn't write to log: " + e.getMessage());
}📋 Practical Task
Building a Persistent High-Score Tracker
Your goal is to create a small program that manages a high score for a game. The program should not lose the data when it restarts.
- Create a file named
highscore.txtthat contains a single integer. - Write a method
int readHighScore()that reads that number from the file. If the file doesn't exist yet, it should return 0. - Write a method
void updateHighScore(int newScore)that reads the existing score and, if thenewScoreis higher, overwrites the file with the new value. - In your
mainmethod, simulate a game: generate a random integer, check if it beats the stored high score, and update the file accordingly.
Challenge: Ensure you are using try-with-resources for both reading and writing to prevent resource leaks.
There are no comments for now.