BufferedReader reads characters efficiently and adds readLine for processing text line by line. BufferedWriter batches character writes and supplies newLine for creating line boundaries. They wrap character streams, so a file's bytes still need the correct charset at the conversion boundary.
Use these classes for text reports, simple line-based configuration or large documents that should not be loaded into one String. This lesson distinguishes an empty line from the end of input, writes a small report, and totals numeric lines from a UTF-8 file.
Buffering and decoding are separate jobs
A Reader turns its source into characters. BufferedReader keeps a character buffer so small reads can be served without repeatedly reaching the underlying source. InputStreamReader handles byte decoding; buffering does not choose or correct that encoding.
Files.newBufferedReader(path, charset) conveniently combines file opening, decoding and buffering. Files.newBufferedWriter supplies the corresponding writer. Specify StandardCharsets.UTF_8 when that is the document's contract rather than relying on a machine-dependent default.
A buffer is not a file-format parser. Reading a line from a CSV document does not automatically identify fields, quoted separators or an embedded newline inside a quoted field. For structured formats, use an appropriate parser after establishing the encoding and resource boundaries.
Buffering also does not mean the complete document is held in memory. The reader normally keeps a limited working buffer, making line-by-line processing suitable for files whose total size would be expensive to load.
Empty text is different from missing input
A blank line is an empty String and may be a valid record, separator or formatting choice. Null means no next line exists. Testing line.isEmpty as the loop's end condition would stop too early when a document contains an intentional blank line.
Decide separately whether to skip blank or whitespace-only lines. String.isBlank recognizes whitespace-only text, while isEmpty only recognizes length zero. A record containing spaces may need preservation rather than normalization if spacing is meaningful in the format.
Trimming text changes the data. It is helpful for a numeric setting that permits surrounding spaces, but harmful for a fixed-width record whose columns depend on position. Apply normalization according to a documented input rule.
Keep a line number when reporting malformed input. A message naming line seventeen and the invalid setting is more useful than an unexplained parsing exception after reading several hundred records.
Flush, close and caller ownership
A write call can leave characters in the writer's buffer. Flush forwards pending characters to the next layer without closing the writer, allowing more content afterward. Close forwards pending content and normally closes the wrapped destination as well.
A locally created file writer should normally be closed with try-with-resources. A helper receiving a caller-owned Writer may be expected to write without closing it. Document ownership so one component does not unexpectedly end another component's document.
Flushing after every short write can defeat buffering. Flush at a useful boundary, such as completing a message that another component must observe, rather than after each character. For a file export, closing at the end is usually the relevant boundary.
Neither flush nor close by itself guarantees physical storage durability against a crash. Treat that stronger requirement as a separate persistence concern, not as a property implied by the word buffered.
Streamed lines, read-ahead and practical limits
BufferedReader.lines provides a stream of line Strings. Processing it still depends on the reader remaining open; put the operation inside the reader's try-with-resources scope. Returning that lazy stream from a method that already closed the reader is a resource-lifetime bug.
mark and reset can revisit recently buffered characters within a documented read-ahead limit. They are useful for limited look-ahead, not a guarantee that you can rewind an arbitrarily large file. Use a fresh reader or a seekable API when the whole document must be revisited.
Line-by-line reading limits whole-document storage, but one enormous line can still consume substantial memory. Applications importing external files should set appropriate input limits. Retaining every line in a list also removes the memory benefit of streaming.
Test the chosen blank-line and newline rules with empty input, one final unterminated line and multiple separators. Those fixtures reveal format assumptions that a single ordinary document can hide.
Buffered Text I/O Summary
- Test null for end-of-input and blankness separately.
- Specify the charset when opening file-backed text.
- Preserve resource lifetime through lazy processing.
- Report parsing errors with a useful line location.
- Continue with JSON processing for structured documents.
Buffered Text I/O Examples
Each example shows the code, the output it produces and what each part does.
Reading blank and nonblank lines
Save this program as ReadingLinesExample.java. An in-memory source makes the line behavior easy to test.
readLine removes the line terminator from its returned String. The output's newline comes from println, not from the original returned text. The trailing newline does not automatically add another empty line after beta; there must be another line's content or terminator to produce that next result.
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.IOException;
public class ReadingLinesExample {
public static void main(String[] args) throws IOException {
String source = "alpha\n\nbeta\n";
try (BufferedReader reader = new BufferedReader(new StringReader(source))) {
String line;
int number = 0;
while ((line = reader.readLine()) != null) {
number++;
System.out.println(number + ": " + line);
}
}
}
}1: alpha
2:
3: betaLine-by-line explanation
- Line 7Two adjacent newline characters create a blank second line.
- Line 11readLine returns null only when the input has ended without another line to supply.
- Lines 12 to 13Every supplied line is counted, including the empty String.
Writing a report with explicit line endings
The writer can also target a StringWriter, keeping formatting tests independent of files.
newLine uses the platform separator, which can differ between operating systems. If a protocol explicitly requires a newline character rather than the platform separator, write that specified character. The reader's line-oriented view and the exact stored line-ending bytes answer different questions.
import java.io.BufferedWriter;
import java.io.StringWriter;
import java.io.IOException;
public class WritingReportExample {
public static void main(String[] args) throws IOException {
StringWriter destination = new StringWriter();
try (BufferedWriter writer = new BufferedWriter(destination)) {
writer.write("Route: P2");
writer.newLine();
writer.write("Stops: 3");
writer.newLine();
}
System.out.print(destination.toString());
}
}Route: P2
Stops: 3Line-by-line explanation
- Lines 7 to 8BufferedWriter wraps a text destination rather than a byte stream.
- Lines 9 to 12Each newLine adds the platform line separator after a complete report line.
- Lines 13 to 14Closing flushes pending characters before the finished report is inspected.
Processing numeric file lines
This program totals nonblank lines and rejects malformed numbers instead of inventing a value.
For a reusable importer, catch NumberFormatException at the parsing boundary and include the line number in a meaningful error. Do not confuse it with IOException, which signals a storage or stream problem. The demonstration propagates both failures so it never announces a successful total for invalid input.
import java.io.BufferedReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
public class NumericLinesExample {
public static void main(String[] args) throws Exception {
Path file = Files.createTempFile("measurements-", ".txt");
try {
Files.write(file, List.of("11", " ", "7"), StandardCharsets.UTF_8);
int total = 0;
int count = 0;
try (BufferedReader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
String line;
while ((line = reader.readLine()) != null) {
if (line.isBlank()) continue;
total += Integer.parseInt(line.strip());
count++;
}
}
System.out.println(count);
System.out.println(total);
} finally {
Files.deleteIfExists(file);
}
}
}2
18Line-by-line explanation
- Lines 9 to 11An isolated UTF-8 fixture contains two measurements and a whitespace-only line.
- Lines 16 to 19Blank lines are skipped by policy; remaining text is stripped and parsed.
- Lines 22 to 23Two accepted measurements sum to eighteen.
- Lines 24 to 25The temporary fixture is removed after the reader closes.
Buffered Text I/O FAQ
Is BufferedReader better than Scanner for every task?
No. Scanner adds token parsing and delimiter rules, while BufferedReader provides character and line access. Choose the abstraction matching the format and your parsing requirements.
Can BufferedWriter append to an existing file?
Yes when the underlying file-opening options specify append. The writer's buffering behavior and the file's overwrite-or-append policy are separate decisions.
Does readLine include the line break?
No. readLine returns the text of the line without its terminator, whether the file uses \n, \r\n or a lone \r. When writing the lines back out, add the line endings yourself with newLine() or an explicit \n.
Should I use newLine() or write "\n"?
newLine() writes the operating system's line separator, which is \r\n on Windows and \n elsewhere. If the file format or the program reading it expects one specific ending, as many data formats do, write that ending explicitly so the output is the same on every computer.
How big is BufferedReader's buffer?
By default it holds 8,192 characters, and the constructor accepts a different size. The default suits almost every program; the big improvement comes from buffering at all, not from tuning the number.
Buffered Text I/O Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
What does readLine return for a blank line?
NumericLinesExample reads 11, a blank line, and 7. How many measurements are accepted?
Buffered Text I/O Quiz
2 questions to check what you learned.
Does readLine keep the original newline character in the returned String?
- No
- Always
- Only for UTF-8
Why must a lines stream be consumed before its reader closes?
- It obtains lines lazily from that reader
- It copies the whole file immediately
- It automatically opens another file