FileWriter
FileWriter is a convenience class for writing characters to a file, extending OutputStreamWriter with a FileOutputStream underneath. It encodes Java characters into bytes using the platform's default charset (or an explicit charset since Java 11) and writes them to a named file or File object. FileWriter supports two modes: overwrite (the default, which truncates the file to zero length on opening) and append (which positions the write pointer at the end of the existing file content). Like FileReader, FileWriter is unbuffered — each write() call propagates immediately to the underlying FileOutputStream, triggering system calls. In practice, FileWriter is almost always wrapped in a BufferedWriter to batch writes into efficient OS calls. The charset trap is identical to FileReader: pre-Java-11 constructors use the platform default charset silently, which causes portability problems; Java 11 constructors accept an explicit Charset. This entry covers all constructor variants with their charset and append semantics, the write methods and their character vs string behavior, newLine() in BufferedWriter, the flush/close contract, and the preferred modern alternatives.
Constructors — Charset, Append Mode, and the Overwrite Default
// ── Pre-Java-11 constructors: implicit platform default charset ────────
FileWriter legacy1 = new FileWriter("output.txt"); // overwrite, default charset
FileWriter legacy2 = new FileWriter("output.txt", true); // append, default charset
FileWriter legacy3 = new FileWriter(new File("output.txt")); // overwrite, default charset
FileWriter legacy4 = new FileWriter(new File("output.txt"), true); // append, default charset
// ── Java 11+: explicit charset ────────────────────────────────────────
FileWriter utf8Overwrite = new FileWriter("output.txt", StandardCharsets.UTF_8);
FileWriter utf8Append = new FileWriter("output.txt", StandardCharsets.UTF_8, true);
FileWriter isoOverwrite = new FileWriter(new File("output.txt"), StandardCharsets.ISO_8859_1);
FileWriter isoAppend = new FileWriter(new File("output.txt"), StandardCharsets.ISO_8859_1, true);
// ── Overwrite (truncate) default — a common source of data loss ────────
File important = new File("important_data.txt");
// File has 1MB of data
try (FileWriter fw = new FileWriter(important, StandardCharsets.UTF_8)) {
// File is NOW EMPTY — truncated on open, BEFORE any write
// If fw.write() throws, the 1MB of data is gone permanently
fw.write("replacement content");
}
// ── Safe overwrite pattern: write to temp, then rename ────────────────
File target = new File("important_data.txt");
File temp = new File("important_data.txt.tmp");
try (FileWriter fw = new FileWriter(temp, StandardCharsets.UTF_8)) {
fw.write("new content");
} // temp file fully written and closed
temp.renameTo(target); // atomic on most OS/filesystems — target replaced atomically
// ── Append mode: add to existing file ────────────────────────────────
// Log file: accumulate entries without truncating
try (FileWriter logger = new FileWriter("app.log", StandardCharsets.UTF_8, true)) {
logger.write(LocalDateTime.now() + " INFO Application started
");
} // existing log content preserved, new line added at end
// Multiple appends accumulate:
for (int i = 0; i < 5; i++) {
try (FileWriter fw = new FileWriter("count.txt", StandardCharsets.UTF_8, true)) {
fw.write("Line " + i + "
");
}
}
// count.txt contains all 5 lines after 5 separate opens
// ── What charset to use? ──────────────────────────────────────────────
// UTF-8: best default — encodes all Unicode, most common on modern systems
// ISO-8859-1: Western European legacy files, 1 byte per char
// UTF-16: fixed-width for BMP chars, rarely needed
// US-ASCII: 7-bit only, throws on any non-ASCII char
// windows-1252: Windows legacy Western European files
System.out.println(StandardCharsets.UTF_8); // always available, no checked exceptionWrite Methods, BufferedWriter Wrapping, and newLine()
// ── FileWriter write methods ──────────────────────────────────────────
try (FileWriter fw = new FileWriter("chars.txt", StandardCharsets.UTF_8)) {
fw.write('A'); // write single char (via int)
fw.write(65); // same: 'A' (Unicode code point 65)
fw.write("Hello, World!"); // write entire string
fw.write("Hello, World!", 7, 5); // write "World" (offset=7, count=5)
char[] letters = {'J', 'a', 'v', 'a'};
fw.write(letters); // write entire char array
fw.write(letters, 0, 2); // write "Ja" (offset=0, count=2)
}
// ── ALWAYS wrap FileWriter in BufferedWriter ───────────────────────────
// Unbuffered: one system call per write — extremely slow for many writes
try (FileWriter fw = new FileWriter("slow.txt", StandardCharsets.UTF_8)) {
for (int i = 0; i < 100_000; i++) {
fw.write("Line " + i + "
"); // each call goes to OS — 100,000 system calls
}
}
// Buffered: system calls reduced to ~12 (100,000 lines × ~50 chars / 8192 buffer)
try (BufferedWriter bw = new BufferedWriter(
new FileWriter("fast.txt", StandardCharsets.UTF_8))) {
for (int i = 0; i < 100_000; i++) {
bw.write("Line " + i);
bw.newLine(); // platform-appropriate line ending
}
} // close() flushes remaining buffer — all lines written
// ── newLine() vs hardcoded
─────────────────────────────────────────
try (BufferedWriter bw = new BufferedWriter(
new FileWriter("platform.txt", StandardCharsets.UTF_8))) {
bw.write("First line");
bw.newLine(); //
on Windows,
on Unix — correct for platform tools
bw.write("Second line");
bw.write("
"); // always
— correct for cross-platform text/JSON/CSV/HTTP
}
// ── PrintWriter: adds printf and println over FileWriter ───────────────
try (PrintWriter pw = new PrintWriter(new BufferedWriter(
new FileWriter("report.txt", StandardCharsets.UTF_8)))) {
pw.println("Report generated: " + LocalDate.now()); // platform newLine
pw.printf("Total: %d items, $%.2f%n", 42, 1234.56); // formatted output
pw.println(); // blank line
}
// ── Modern alternative: Files.writeString and Files.write ─────────────
// Write entire string at once (no intermediate FileWriter needed):
Files.writeString(Path.of("output.txt"), "Hello, UTF-8 World!",
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
// Write lines (adds platform line separator after each):
List<String> lines = List.of("Line 1", "Line 2", "Line 3");
Files.write(Path.of("lines.txt"), lines, StandardCharsets.UTF_8);
// Append with Files.writeString:
Files.writeString(Path.of("log.txt"), "New entry
",
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND);