- Writing to text file in java
- Writing individual bytes with FileOutputStream
- Writing byte arrays with FileOutputStream
- Writing binary data with the NIO.2 OutputStream
- Write faster with BufferedOutputStream
- Writing byte arrays with BufferedOutputStream
- Writing text files with FileWriter
- Write text files faster with BufferedWriter
- Write text files faster with the NIO.2 BufferedWriter
- Performance overview: writing files
- Overview FileOutputStream, FileWriter, OutputStreamWriter, BufferedOutputStream, BufferedWriter
- Character encoding
- What character encoding does Java use by default to write text files?
- How to specify the character encoding when writing a text file?
- Summary and outlook
- Java Create and Write To Files
- Example
- Example
- Write To a File
- Example
Writing to text file in java
To progressively write data to a file, use a FileOutputStream (or related classes). These were available before Java 7 and made writing small files unnecessarily complicated. In the following sections, I present various options.
Writing individual bytes with FileOutputStream
The primary class is FileOutputStream . It writes data byte by byte into a file. The following example shows how bytes returned by the process() method are successively written to a file (until the method returns -1):
String fileName = . ; try (FileOutputStream out = new FileOutputStream(fileName)) < int b; while ((b = process()) != -1) < out.write(b); > >
Code language: GLSL (glsl)
Writing individual bytes is an expensive operation. Writing 100,000,000 bytes to a test file takes about 230 seconds on my system; that’s just a little more than 0.4 MB per second.
Writing byte arrays with FileOutputStream
Using FileOutputStream , you can also write byte arrays. In the following example, the process() method returns byte arrays instead of individual bytes (and null if no more data is available):
String fileName = . ; try (FileOutputStream out = new FileOutputStream(fileName)) < byte[] bytes; while ((bytes = process()) != null) < out.write(bytes); >>
Code language: GML (gml)
This method is several times faster. If you write 10 bytes 10,000,000 times (the same amount in total), you only need 24 seconds, a little more than a tenth of the previous time. If you write 100 bytes 1,000,000 times, it’s only 2.6 seconds, which is a little more than a hundredth of the previous time. What is relevant here is primarily the number of write operations, not the actual amount of data. This is because the data is written block-wise to the storage medium. Naturally, this only applies up to a specific buffer size. Writing ten gigabytes at a time is no faster than writing ten times one gigabyte. The optimal value for the buffer size depends on the hardware as well as the formatting of the medium. Using a small test program, I measured the write speed in relation to the buffer size:
On my system, the optimal buffer size is 8 KB. At this size, the write speed reaches 1,050 MB per second. 8 KB is also the optimal size on most other systems, which is why Java uses this value as default, as you can see in a later section.
Writing binary data with the NIO.2 OutputStream
String fileName = . ; try (OutputStream out = Files.newOutputStream(Path.of(fileName))) < int b; while ((b = process()) != -1) < out.write(b); >>
Code language: Java (java)
This method returns a ChannelOutputStream instead of a FileOutputStream . On my system, there is no relevant speed difference compared to new FileOutputStream() when writing individual bytes or byte blocks.
Write faster with BufferedOutputStream
We have previously observed that writing blocks is much faster than writing individual bytes. BufferedOutputStream takes advantage of this fact by first buffering the bytes to be written in a buffer and then writing them to disk when the buffer is full. By default, this buffer is 8 KB in size, which is precisely the size that leads to optimal write speed.
String fileName = . ; try (FileOutputStream out = new FileOutputStream(fileName); BufferedOutputStream bout = new BufferedOutputStream(out)) < int b; while ((b = process()) != -1) < bout.write(b); >>
Code language: GLSL (glsl)
Using BufferedOutputStream , my system needs about 250 ms to write 100,000,000 individual bytes. That’s about 400 MB per second. The reason we’re not reaching the 1,050 MB/s from the previous test is the overhead of the buffering logic.
Writing byte arrays with BufferedOutputStream
Just like FileOutputStream , BufferedOutputStream can write not only individual bytes but also byte blocks:
String fileName = . ; try (FileOutputStream out = new FileOutputStream(fileName); BufferedOutputStream bout = new BufferedOutputStream(out)) < byte[] bytes; while ((bytes = process()) != null) < bout.write(bytes); >>
Code language: Java (java)
This method combines the advantages of writing byte arrays with those of a buffer. It almost always delivers optimum write speeds. For writing binary data, I always recommend using this method.
Writing text files with FileWriter
For writing text to a file, it must be converted to binary data. Character-to-byte conversion is the OutputStreamWriter ‘s responsibility. You wrap it around the FileOutputStream as follows. The process() method in the following example produces individual characters.
String fileName = . ; try (FileOutputStream out = new FileOutputStream(fileName); OutputStreamWriter writer = new OutputStreamWriter(out)) < int c; while ((c = process()) != -1) < writer.write(c); >>
Code language: Java (java)
FileWriter is more convenient. It combines FileOutputStream and OutputStreamWriter . The following code is equivalent to the previous one:
String fileName = . ; try (FileWriter writer = new FileWriter(fileName)) < int c; while ((c = process()) != -1) < writer.write(c); >>
Code language: Java (java)
OutputStreamWriter also uses an 8 KB buffer internally. Writing 100,000,000 characters to a text file takes about 2.5 seconds.
Write text files faster with BufferedWriter
String fileName = . ; try (FileWriter writer = new FileWriter(fileName); BufferedWriter bufferedWriter = new BufferedWriter(writer)) < int c; while ((c = process()) != -1) < bufferedWriter.write(c); >>
Code language: Java (java)
BufferedWriter adds another 8 KB buffer for characters, which are then encoded in one go when the buffer is written (instead of character by character). This second buffer reduces the writing time for 100,000,000 characters to approximately 370 ms.
Write text files faster with the NIO.2 BufferedWriter
String fileName = . ; try (BufferedWriter bufferedWriter = Files.newBufferedWriter(Path.of(fileName))) < int c; while ((c = process()) != -1) < bufferedWriter.write(c); >>
Code language: Java (java)
The write speed on my system is about the same as the speed of the «classically» created BufferedWriter .
Performance overview: writing files
In the following diagram, you can see how much time the methods presented need to write 100,000,000 bytes or characters into a binary or text file:
Due to the large gap between unbuffered and buffered writing, the buffered methods hardly stand out here. The following diagram, therefore, only shows the methods that use a buffer:
Overview FileOutputStream, FileWriter, OutputStreamWriter, BufferedOutputStream, BufferedWriter
The following diagram shows the context of the java.io classes presented in this article for writing binary and text files:
Solid lines represent binary data; dashed lines represent text data. FileWriter combines FileOutputStream and OutputStreamWriter .
Character encoding
The subject of character encoding and the problems that go with it have been discussed in detail in the previous article. Therefore, I’ve limited the following sections to those aspects that are relevant for writing text files with Java.
What character encoding does Java use by default to write text files?
- The FileWriter and OutputStreamWriter classes internally use StreamEncoder.forOutputStreamWriter() . If you call this method without a specific character encoding, it uses Charset.defaultCharset() . This method, in turn, reads the character encoding from the system property «file.encoding». If the system property is not specified, it uses ISO-8859-1 by default up to Java 5 and UTF-8 since Java 6.
- The Files.writeString() , Files.write() and Files.newBufferedWriter() methods all use UTF-8 as default encoding without reading the system property mentioned above.
Due to these inconsistencies, you should always specify the character encoding. I always recommend using UTF-8. According to Wikipedia, UTF-8 encoding is used on 94.4% of all websites and can, therefore, be regarded as a de-facto standard. An exception is, of course, when you have to work with old files written in a different encoding.
How to specify the character encoding when writing a text file?
In the following you will find an example for all methods discussed so far with the character encoding set to UTF-8:
- Files.writeString(path, string, StandardCharsets.UTF_8)
- Files.write(path, lines, StandardCharsets.UTF_8)
- new FileWriter(file, StandardCharsets.UTF_8) // this method only exists since Java 11
- new InputStreamWriter(outputStream, StandardCharsets.UTF_8)
- Files.newBufferedWriter(path, StandardCharsets.UTF_8)
Summary and outlook
This article has shown different methods for writing byte arrays and Strings in binary and text files in Java.
In future articles of this series, I will show:
In the further course of the series, more advanced topics will be covered:
- The NIO channels and buffers introduced in Java 1.4 to speed up working with large files in particular .
- Memory-mapped I/O for ultra-fast file access without streams.
- File locking to access the same files from multiple threads or processes in parallel without conflict.
Would you like to be informed when future articles are published? Then click here to sign up for the HappyCoders newsletter. If you liked the article, I’m also happy if you share it via one of the buttons at the end.
Java Create and Write To Files
To create a file in Java, you can use the createNewFile() method. This method returns a boolean value: true if the file was successfully created, and false if the file already exists. Note that the method is enclosed in a try. catch block. This is necessary because it throws an IOException if an error occurs (if the file cannot be created for some reason):
Example
import java.io.File; // Import the File class import java.io.IOException; // Import the IOException class to handle errors public class CreateFile < public static void main(String[] args) < try < File myObj = new File("filename.txt"); if (myObj.createNewFile()) < System.out.println("File created: " + myObj.getName()); >else < System.out.println("File already exists."); >> catch (IOException e) < System.out.println("An error occurred."); e.printStackTrace(); >> >
To create a file in a specific directory (requires permission), specify the path of the file and use double backslashes to escape the » \ » character (for Windows). On Mac and Linux you can just write the path, like: /Users/name/filename.txt
Example
File myObj = new File("C:\\Users\\MyName\\filename.txt");
Write To a File
In the following example, we use the FileWriter class together with its write() method to write some text to the file we created in the example above. Note that when you are done writing to the file, you should close it with the close() method:
Example
import java.io.FileWriter; // Import the FileWriter class import java.io.IOException; // Import the IOException class to handle errors public class WriteToFile < public static void main(String[] args) < try < FileWriter myWriter = new FileWriter("filename.txt"); myWriter.write("Files in Java might be tricky, but it is fun enough!"); myWriter.close(); System.out.println("Successfully wrote to the file."); >catch (IOException e) < System.out.println("An error occurred."); e.printStackTrace(); >> >
To read the file above, go to the Java Read Files chapter.