Java Write to File: Clean Code vs. Performance

When working on an enterprise application, sometimes it is necessary to write the text or binary data into files in Java e.g. writing user-generated reports into the filesystem.

Though there are multiple ways of writing the files in Java, let’s quickly go through a few of them for quick reference when it is needed.

String content = "some text";

// Java 11
Files.writeString(Path.of("demo.txt"), content);    

// Using Files class
Files.write(Path.of("demo.txt"), content.getBytes());   

// Using BufferedWriter
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath.toFile()))) {  
  writer.write(content);
}

// Using FileWriter
try(FileWriter fileWriter = new FileWriter(Path.of("demo.txt").toFile())){
  fileWriter.write(content);
}

// Write to binary file
try(FileOutputStream outputStream = new FileOutputStream(Path.of("demo.txt").toFile())){
  byte[] strToBytes = content.getBytes();
  outputStream.write(strToBytes);
}

1. Using Files.writeString() – Java 11

Starting with Java 11, the Files.writeString() method offers a convenient way to write text to a file. It accepts a Path parameter and a string, simplifying the process of writing text content in a single-line statement.

  • As the name suggests, writeString() method is used to write the character/text data into files.
  • All characters are written as they are, including the line separators. No extra characters are added.
  • By default, UTF-8 character encoding is used.
  • It throws IOException if an I/O error occurs when writing to or creating the file, or if the text cannot be encoded using the specified charset.
Path filePath = Path.of("demo.txt");
String content  = "hello world !!";

Files.writeString(filePath, content);

2. Write to File using Files.write()

Files class is another method write() since Java 7 and it works similarly to writeString(). It takes a Path and a byte array as parameters.

The write() method is suitable for writing binary data as well as it can also be used for writing text data, as shown in the following example.

Path filePath = Path.of("demo.txt");
String content  = "hello world !!";

//Write bytes
Files.write(filePath, content.getBytes());

//Write lines
List<String> lines = Arrays.asList("a", "b", "c");
Files.write(filePath, lines, StandardCharsets.UTF_8);

3. Fast Writing with FileChannel and ByteBuffer

FileChannel can be used for reading, writing, mapping, and manipulating a file. If we are writing large files, FileChannel can be faster than standard IO.

File channels are safe for use by multiple concurrent threads.

Path fileName = Path.of("demo.txt");
String content  = "hello world !!";

try (
  RandomAccessFile stream = new RandomAccessFile(filePath.toFile(),"rw");
  FileChannel channel = stream.getChannel();) {

  byte[] strBytes = content.getBytes();
  ByteBuffer buffer = ByteBuffer.allocate(strBytes.length);

  buffer.put(strBytes);
  buffer.flip();
  channel.write(buffer);
}

4. Write to Text File with BufferedWriter

BufferedWriter the most traditional and simplest way to write the content to a file. It writes text to a character-output stream, buffering characters so as to provide for the efficient writing of single characters, arrays, and strings.

Unless prompt output is required, it is advisable to wrap a BufferedWriter around any Writer whose write() operations may be costly, such as FileWriter and OutputStreamWriter, especially when writing large amounts of data.

As it buffers before writing, it results in fewer IO operations, so it improves the performance.

Path filePath = Path.of("demo.txt");
String content  = "hello world !!";

try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath.toFile()))) {

  writer.write(content);
}

5. Write to File with FileWriter or PrintWriter

FileWriter the cleanest way to write files and the syntax is self-explanatory and easy to read and understand. FileWriter writes directly into the file (less performance) and should be used only when the number of writes is less.

Because the FileWriter does not offer buffering, it can lead to performance issues when writing large amounts of data.

Path filePath = Path.of("demo.txt");
String content  = "hello world !!";

try(FileWriter fileWriter = new FileWriter(filePath.toFile())){

  fileWriter.write(content);
}

Use PrintWriter to write formatted text to a file. This class implements all of the print methods found in PrintStream, so you can use all formats that you use with System.out.println() statements.

Path filePath = Path.of("demo.txt");
String content  = "hello world !!";

try(FileWriter fileWriter = new FileWriter(filePath.toFile());
  PrintWriter printWriter = new PrintWriter(fileWriter);){

  printWriter.print(content);
  printWriter.printf("Blog name is %s", "howtodoinjava.com");
}

6. Write to Binary File with FileOutputStream

Use FileOutputStream to write binary data to a file. FileOutputStream is meant for writing streams of raw bytes such as image data. For writing streams of characters, consider using FileWriter.

Path filePath = Path.of("demo.txt");
String content  = "hello world !!";

try(FileOutputStream outputStream = new FileOutputStream(filePath.toFile())){
  
  byte[] strToBytes = content.getBytes();
  outputStream.write(strToBytes);
}

7. Write to File with DataOutputStream

DataOutputStream lets an application write primitive Java data types to an output stream in a portable way. An application can then use a data input stream to read the data back in.

Path filePath = Path.of("demo.txt");
String content  = "hello world !!";

try (
  FileOutputStream outputStream 
    = new FileOutputStream(filePath.toFile());
  DataOutputStream dataOutStream 
    = new DataOutputStream(new BufferedOutputStream(outputStream));) {
    
  dataOutStream.writeUTF(content);
  dataOutStream.writeInt(10);
  dataOutStream.writeLong(100L);
} 

7. Clean Code vs. Performance

When considering performance, there are several factors to take into account:

  • Convenience: Files.writeString() is the most convenient for writing text data, while Files.write() is suitable for binary data. These methods provide an easy-to-use API.
  • Buffering: BufferedWriter and Files.write() provide buffering, which can significantly improve write performance, especially when dealing with large amounts of data.
  • Binary vs. Text Data: If you need to write binary data, FileOutputStream is the best choice. For text data, the decision depends on the level of convenience and the need for buffering as discussed above.

For smaller files, we may prefer readability weighing over other factors because the performance gains will be negligible. Ther FileWriter and Files.writeString() should be preferred choices in case of smaller files.

For a large amount of data, we will require a better raw performance. In this case, buffered methods like BufferedWriter and Files.write() can offer improved efficiency.

Ultimately, the choice of method should depend on the specific requirements, such as data volume, simplicity, and readability.

8. Summary

  • If we try to write to a file that doesn’t exist, the file will be created first and no exception will be thrown (except using Path method).
  • Always close the output stream after writing the file content to release all resources. It will also help in not corrupting the file.
  • Use PrintWriter is used to write formatted text.
  • Use FileOutputStream to write binary data.
  • Use DataOutputStream to write primitive data types.
  • Use FileChannel to write larger files. It is the preferred way of writing files in Java 8 as well.

Happy Learning !!

Source Code on Github

Comments

Subscribe
Notify of
guest
1 Comment
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode