Learn Java

How to Write to a File in Java

By Updated 8 min read

In Java 11 and later, the simplest way to write text to a file is Files.writeString(Path.of("out.txt"), text), which creates the file if it does not exist and replaces everything in it if it does. Every example on this page runs right here on a small disk that lives in your browser, so you can press Run and watch the file fill up. After the short way come appending, the classic writers (FileWriter, BufferedWriter and PrintWriter), why a file can come out empty, and how to create files and folders.

Main.java
1import java.io.IOException;
2import java.nio.file.Files;
3import java.nio.file.Path;
4
5public class Main {
6 public static void main(String[] args) throws IOException {
7 Path file = Path.of("out.txt");
8 Files.writeString(file, "Hello, file!\nThis is line two.\n");
9
10 System.out.print(Files.readString(file));
11 }
12}
Prints
›Hello, file!
›This is line two.

Step to the end and the memory view shows out.txt holding two lines; the last line of the program reads the file back, so the text also appears as output. Path.of turns the name into a Path, Java's object for where a file is, and writeString opens the file, writes the text and closes the file in that one call, so there is nothing left for you to close.

writeString writes exactly the characters you give it and adds no line break of its own, so end each line with \n. Writing can fail, on a full disk or in a read-only folder, and the failure is an IOException, a checked exception that Java makes you catch or declare. Here main declares it with throws IOException. writeString arrived in Java 11. On Java 8, Files.write(path, text.getBytes(StandardCharsets.UTF_8)) does the same job.

Write a list of lines with Files.write#

When your text is a list of lines, Files.write(path, lines) writes each element and ends it with a line break, the last one included. This program builds a shopping list and saves it:

Main.java
1import java.io.IOException;
2import java.nio.file.Files;
3import java.nio.file.Path;
4import java.util.ArrayList;
5import java.util.List;
6
7public class Main {
8 public static void main(String[] args) throws IOException {
9 String[] items = {"bread", "eggs", "coffee"};
10
11 List<String> lines = new ArrayList<>();
12 for (String item : items) {
13 lines.add("- " + item);
14 }
15
16 Files.write(Path.of("shopping.txt"), lines);
17 System.out.print(Files.readString(Path.of("shopping.txt")));
18 }
19}
Prints
›- bread
›- eggs
›- coffee

Like writeString, Files.write creates the file or replaces it, and closes it before it returns. The list can come from anywhere: a loop, as here, or the lines you read from another file.

Append to a file instead of replacing it#

Every way of writing a file replaces what was in it, unless you ask to append, which adds your text after the old contents. With the Files methods, pass StandardOpenOption.CREATE and StandardOpenOption.APPEND. With FileWriter, pass true as a second argument. This log.txt starts with a line from Sunday, and the program adds a line each way:

Main.java
1import java.io.FileWriter;
2import java.io.IOException;
3import java.nio.file.Files;
4import java.nio.file.Path;
5import java.nio.file.StandardOpenOption;
6
7public class Main {
8 public static void main(String[] args) throws IOException {
9 Path log = Path.of("log.txt");
10
11 Files.writeString(log, "Monday: opened\n",
12 StandardOpenOption.CREATE, StandardOpenOption.APPEND);
13
14 try (FileWriter writer = new FileWriter("log.txt", true)) {
15 writer.write("Monday: closed\n");
16 }
17
18 System.out.print(Files.readString(log));
19 }
20}
Files before the program runs
log.txt
Sunday: opened
Prints
›Sunday: opened
›Monday: opened
›Monday: closed

Sunday's line stays, and the two new lines land after it. APPENDon its own means “add to a file that exists”, so on a first run, before the file exists, it throws java.nio.file.NoSuchFileException: log.txt. CREATE makes the file when it is missing. new FileWriter("log.txt", true) creates a missing file by itself.

WayReplace the fileAdd to the end
Files.writeStringwriteString(path, text)writeString(path, text, CREATE, APPEND)
Files.writewrite(path, lines)write(path, lines, CREATE, APPEND)
Files.newBufferedWriternewBufferedWriter(path)newBufferedWriter(path, CREATE, APPEND)
FileWriternew FileWriter("log.txt")new FileWriter("log.txt", true)
BufferedWriter, PrintWriterWrap new FileWriter("log.txt")Wrap new FileWriter("log.txt", true)
CREATE and APPEND are StandardOpenOption.CREATE and StandardOpenOption.APPEND, from java.nio.file.
Opening without append empties the file at once
A file opened for writing without append loses its old contents straight away, before you write a single character, with no warning and no undo. Forget the true or the APPEND when you add to a log, and the whole log is gone.

Write to a file with FileWriter and BufferedWriter#

FileWriter is the classic class for writing text to a file: open it with a file name, call write, close it. Wrapped in a BufferedWriter, it gains newLine(), which ends the current line, and its many small writes are gathered into a few large ones, which is faster. This program writes a list of names, one per line:

Main.java
1import java.io.BufferedWriter;
2import java.io.FileWriter;
3import java.io.IOException;
4import java.nio.file.Files;
5import java.nio.file.Path;
6
7public class Main {
8 public static void main(String[] args) throws IOException {
9 String[] names = {"Aisha", "Ben", "Carmen"};
10
11 try (BufferedWriter writer = new BufferedWriter(new FileWriter("names.txt"))) {
12 for (String name : names) {
13 writer.write(name);
14 writer.newLine();
15 }
16 }
17
18 System.out.print(Files.readString(Path.of("names.txt")));
19 }
20}
Prints
›Aisha
›Ben
›Carmen

Step through it and watch the Files section of the memory view. names.txt appears, empty, the moment FileWriter opens it. Each write and newLine()only adds to the writer's buffer, and all three names reach the file together when the try block ends and closes the writer. write never adds a line break by itself: without the newLine() calls the file would hold AishaBenCarmen.

The writer is declared in the parentheses after try, a form called try-with-resources: Java closes it when the block ends, even if an exception ends it early. Files.newBufferedWriter(Path.of("names.txt")) gives you the same kind of writer from a Path.

write(91) writes a character, not a number
write has a version that takes an int and treats it as a character code, so writer.write(91) writes [, the character with code 91. Turn a number into text first, as in writer.write("Score: " + 91), or use a PrintWriter, whose println(91) writes the digits.

Write to a file with PrintWriter#

PrintWriter gives a file the print, println and printf methods you know from System.out. printf lines text up in columns: %-6s pads a string with spaces to 6 characters, %5d writes a whole number right-aligned in 5, and %n ends the line.

Main.java
1import java.io.FileWriter;
2import java.io.IOException;
3import java.io.PrintWriter;
4import java.nio.file.Files;
5import java.nio.file.Path;
6
7public class Main {
8 public static void main(String[] args) throws IOException {
9 String[] names = {"Ada", "Grace", "Alan"};
10 int[] scores = {91, 88, 79};
11
12 try (PrintWriter out = new PrintWriter(new FileWriter("scores.txt"))) {
13 out.println("Name Score");
14 for (int i = 0; i < names.length; i++) {
15 out.printf("%-6s %5d%n", names[i], scores[i]);
16 }
17 }
18
19 System.out.print(Files.readString(Path.of("scores.txt")));
20 }
21}
Prints
›Name Score
›Ada 91
›Grace 88
›Alan 79

The file gets a heading and three rows with the scores lined up under it. Use the form new PrintWriter(new FileWriter(name)), because the FileWriter inside can take true to append. new PrintWriter("scores.txt") works too, but always replaces the file. Unlike the other writers, PrintWriter's methods never throw an IOException, so a failed write goes unnoticed unless you call checkError(), which returns true once anything has gone wrong.

Why is my file empty? Close or flush the writer#

A writer keeps your text in a buffer, a holding area in memory, and sends it to the disk in large batches, because each trip to the disk is slow. The text reaches the file only when the buffer fills up, when you call flush(), or when you call close(), which flushes first. This program never closes its writer:

Main.java
1import java.io.FileWriter;
2import java.io.IOException;
3import java.nio.file.Files;
4import java.nio.file.Path;
5
6public class Main {
7 public static void main(String[] args) throws IOException {
8 FileWriter writer = new FileWriter("diary.txt");
9 writer.write("Dear diary,\n");
10 writer.write("Today I wrote my first file.\n");
11
12 System.out.println("Bytes in diary.txt: " + Files.size(Path.of("diary.txt")));
13 }
14}
Prints
›Bytes in diary.txt: 0

Both write calls succeed, yet the program prints Bytes in diary.txt: 0. Step to the end and the narration says the text was still in writer's buffer when the program finished, so it never reached the file. Open the program in the playground (the button next to Run), add writer.close(); above the println, and run it again: the file then holds 41 bytes. A plain FileWriter buffers like this, and so do BufferedWriter and PrintWriter.

Key idea

Your text is in the file only after flush() or close(). Open every writer in try-with-resources and Java closes it for you, even when an exception ends the block early.

flush()
close()
Sends the buffered text to the file now.
Sends the buffered text to the file, then releases the file.
The writer stays open, so you can keep writing.
The writer is finished. Another write on a FileWriter or BufferedWriter throws java.io.IOException: Stream closed.
Use it to save progress while you keep writing, as a long-running log does.
Use it once, when you are done. try-with-resources calls it for you.

Writing files walks through buffers, flush() and close() step by step.

How to create a file in Java#

Usually you need no separate step: Files.writeString, Files.write, FileWriter and PrintWriter all create the file when it does not exist. Create a file on its own when you want it empty, or when you must not replace a file that is already there. File.createNewFile() returns true if it made the file and false if the file was already there, while Files.createFile throws a FileAlreadyExistsException. This disk starts with a notes.txt:

Main.java
1import java.io.File;
2import java.io.IOException;
3import java.nio.file.FileAlreadyExistsException;
4import java.nio.file.Files;
5import java.nio.file.Path;
6
7public class Main {
8 public static void main(String[] args) throws IOException {
9 File todo = new File("todo.txt");
10 System.out.println("Created todo.txt? " + todo.createNewFile());
11 System.out.println("Created it again? " + todo.createNewFile());
12
13 try {
14 Files.createFile(Path.of("notes.txt"));
15 } catch (FileAlreadyExistsException e) {
16 System.out.println("Not created: " + e);
17 }
18 }
19}
Files before the program runs
notes.txt
Buy milk
Prints
›Created todo.txt? true
›Created it again? false
›Not created: java.nio.file.FileAlreadyExistsException: notes.txt

Each of them checks for the file and creates it in a single step, so no other program can create the same file in between. To write a file only if it is new, pass StandardOpenOption.CREATE_NEW to Files.writeString: it creates the file and writes your text, or throws FileAlreadyExistsException and leaves the old file alone.

Create missing folders with Files.createDirectories#

The writing methods create files, never folders. Writing to reports/2026/march.txt when there is no reports folder stops with java.nio.file.NoSuchFileException: reports/2026/march.txt, which is confusing until you see that the missing piece is the folder. Files.createDirectories makes a folder, and any folders above it that are missing, first:

Main.java
1import java.io.IOException;
2import java.nio.file.Files;
3import java.nio.file.Path;
4
5public class Main {
6 public static void main(String[] args) throws IOException {
7 Path folder = Path.of("reports", "2026");
8 Files.createDirectories(folder);
9
10 Path file = folder.resolve("march.txt");
11 Files.writeString(file, "Sales: 12\n");
12 System.out.println("Wrote " + file);
13 }
14}
Prints
›Wrote reports/2026/march.txt

It prints Wrote reports/2026/march.txt, with backslashes on Windows. createDirectories does nothing for folders that already exist, so it is safe to call on every run, and resolveadds a name to the end of the folder's path.

Which way should you use?#

WayBest forCloses the file itself?
Files.writeString(path, text)A whole file from one StringYes
Files.write(path, lines)A whole file from a list of linesYes
BufferedWriter around a FileWriter, or Files.newBufferedWriterWriting line by line in a loop, big files, a log that stays openNo, use try-with-resources
PrintWriterFormatted text with println and printfNo, use try-with-resources
FileWriter on its ownA few short writes; wrap it in a BufferedWriter for moreNo, use try-with-resources

When the whole text fits in memory, Files.writeString or Files.write is the shortest choice and leaves no writer to forget. Use a writer when the text comes out bit by bit. Path and Files covers the Files methods in depth, and how to read a file in Java shows the way back in.

Character encoding and line endings#

A file stores bytes, and a character encoding is the rule that turns letters into bytes. The Files methods write UTF-8 unless you pass another encoding. Since Java 18 (JEP 400), FileWriter and PrintWriterdefault to UTF-8 too, on every operating system. Before Java 18 they used the computer's own default, which on many Windows machines was not UTF-8, so older code names the encoding: new FileWriter("out.txt", StandardCharsets.UTF_8), a constructor added in Java 11.

newLine(), println, %n and Files.writeend each line with your system's line separator: \n on macOS and Linux, and the two characters \r\n on Windows. A \n you put inside a string stays a single \neverywhere. When you need the system's separator in a string of your own, System.lineSeparator() returns it.

Questions people ask#

How do I write a String to a file in Java?
Call Files.writeString(Path.of("out.txt"), text), which arrived in Java 11. It creates the file if it is missing, replaces anything already in it, and closes the file before it returns.
How do I append to a file instead of overwriting it?
Pass StandardOpenOption.CREATE and StandardOpenOption.APPEND to Files.writeString, or open new FileWriter("log.txt", true). Without them, every way of writing a file replaces what was in it.
Why is my file empty after writing to it?
The writer was never closed or flushed, so the text was still waiting in its buffer in memory when the program ended. Open the writer in a try-with-resources block, or call close() when you finish writing.
How do I create a new file in Java?
Writing to a file that does not exist creates it, so Files.writeString or new FileWriter(name) is usually enough. To create an empty file only if it is new, call new File(name).createNewFile(), which returns false if the file already exists, or Files.createFile(path), which throws FileAlreadyExistsException.
How do I write to a file using PrintWriter?
Open new PrintWriter(new FileWriter("report.txt")) in a try-with-resources block and call println or printf on it, as you would on System.out. Its methods never throw IOException, so call checkError() when you need to know whether a write failed.
What is the difference between FileWriter and BufferedWriter?
FileWriter writes characters to a file. BufferedWriter wraps another writer, gathers many small writes into fewer large ones and adds newLine(), so the usual form is new BufferedWriter(new FileWriter(name)).

Further reading#

Learn it step by step

These lessons teach the topic from the start, with more examples and questions to check yourself.

All guides

Spotted a mistake, or a part that did not make sense? Report it by email