Reading & writing text files
BufferedReader/PrintWriter, the readLine loop, and append-mode logging.
Reading a text file line by line
The everyday way to read text is a BufferedReader wrapped around a FileReader (FileReader is itself a convenience Reader over a file). Its readLine() returns one line at a time (without the line terminator), and returns null at end of file. That null is the loop sentinel:
try (BufferedReader in =
new BufferedReader(new FileReader("examples1.txt"))) {
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
}
Read the loop condition carefully: it assigns in.readLine() to line, then compares the assigned value to null. The assignment is the whole expression's value, so the loop runs as long as a real line came back and stops the moment readLine() hands you null. The try-with-resources header closes the reader automatically.
Writing text
For output, PrintWriter gives you the familiar print, println, and printf/format methods over any Writer or OutputStream. The simplest form opens a file by name:
try (PrintWriter out = new PrintWriter("report.txt")) {
out.println("Greenhouse report");
out.printf("light=%b water=%b%n", true, false);
} // close() flushes and releases the file
Append vs overwrite — the logging case
By default, opening a file for writing truncates it: the old contents are gone. For a log file you almost always want to append instead. Append mode lives on FileWriter, whose second constructor argument is an append flag:
// true => append; the existing log is preserved and new lines are added
try (PrintWriter log =
new PrintWriter(new FileWriter("error.log", true))) {
log.println(System.currentTimeMillis() + ": WindowMalfunction");
}
This is exactly the shape the Greenhouse project uses to write its error.log and fix.log: each fault appends a timestamped line so the history survives across runs. Wrapping FileWriter in PrintWriter keeps the convenient println/printf API while controlling the append flag at the FileWriter layer.