Skip to Content
Course content

92: File I/O with java.io

Click on the "Edit" button in the top corner of the screen to edit your slide content.

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.txt that 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 the newScore is higher, overwrites the file with the new value.
  • In your main method, 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.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.