- How to Read and Write Binary Files in Java
- You might also like.
- How to Read and Write Binary Files in Java
- 1. Understanding Byte Streams
- 2. Reading and Writing Binary Files Using FileInputStream and FileOutputStream
- 3. Reading and Writing Binary Files Using BufferedInputStream and BufferedOutputStream
- 4. Reading and Writing Binary Files Using New File I/O API (NIO)
- API References:
- Related File IO Tutorials:
- Other Java File IO Tutorials:
- About the Author:
How to Read and Write Binary Files in Java
In an earlier article, we looked at reading and writing different types of files in Java. In this short article, you will learn how to read and write binary files in Java.
The following example demonstrates how you can use the FileInputStream class to read a binary file, one byte at a time without any buffering:
try // create a reader FileInputStream fis = new FileInputStream(new File("input.dat")); // read one byte at a time int ch; while ((ch = fis.read()) != -1) System.out.print((char) ch); > // close the reader fis.close(); > catch (IOException ex) ex.printStackTrace(); >
If you are reading a large file, the above program may take some time to complete as it reads only one byte at a time. For better I/O performance, you should use the BufferedInputStream class as it reads a set of bytes all at once into an internal byte array buffer, reducing the number of calls to the disk, hence increasing I/O performance. By default, the internal buffer size is 8KB but we can specify a custom buffer size at the time of initialization. Here is an example that uses BufferedInputStream with default buffer size to read a binary file:
try // create a reader FileInputStream fis = new FileInputStream(new File("input.dat")); BufferedInputStream reader = new BufferedInputStream(fis); // read one byte at a time int ch; while ((ch = reader.read()) != -1) System.out.print((char) ch); > // close the reader reader.close(); > catch (IOException ex) ex.printStackTrace(); >
// custom buffer size int BUFFER_SIZE = 16 * 1024; // 16KB // create a reader FileInputStream fis = new FileInputStream(new File("input.dat")); BufferedInputStream reader = new BufferedInputStream(fis, BUFFER_SIZE);
If your binary file has encoding other the default character encoding of the operating system, or you want to explicitly set an encoding scheme, you have to use the InputStreamReader class instead:
try // create a reader FileInputStream fis = new FileInputStream(new File("input.dat")); // specify UTF_16 characer encoding InputStreamReader reader = new InputStreamReader(fis, StandardCharsets.UTF_16); // read one byte at a time int ch; while ((ch = reader.read()) != -1) System.out.print((char) ch); > // close the reader reader.close(); > catch (IOException ex) ex.printStackTrace(); >
The following example shows how you can use the FileOutputStream class to write data to a binary file in Java:
try // create a writer FileOutputStream fos = new FileOutputStream(new File("output.dat")); // write data to file fos.write("Hey, there!".getBytes()); fos.write("\n".getBytes()); fos.write("How are you doing?".getBytes()); // close the writer fos.close(); > catch (IOException ex) ex.printStackTrace(); >
The above example works perfect but every time the write() method is called, an I/O operation to the disk is performed. It may not be a desirable solution for writing large-sized files. To reduce the number of I/O operations and improve performance, you should use the BufferedOutputStream class instead. Just like BufferedInputStream , it uses an internal buffer of size 8KB (can be customized) to store the data and only writes to the disk when the buffer is full. Here is an example that uses BufferedOutputStream with default buffer size to write data to a binary file:
try // create a writer FileOutputStream fos = new FileOutputStream(new File("output.dat")); BufferedOutputStream writer = new BufferedOutputStream(fos); // write data to file writer.write("Hey, there!".getBytes()); writer.write("\n".getBytes()); writer.write("How are you doing?".getBytes()); // flush remaining bytes writer.flush(); // close the writer writer.close(); > catch (IOException ex) ex.printStackTrace(); >
Notice the writer.flush() method call in the above code. You must call this method before closing the BufferedOutputStream instance to make sure that the remaining data in the internal buffer is flushed to the disk. You can also specify a custom internal buffer size like below:
// custom buffer size int BUFFER_SIZE = 16 * 1024; // 16KB // create a writer FileOutputStream fos = new FileOutputStream(new File("output.dat")); BufferedOutputStream writer = new BufferedOutputStream(fos, BUFFER_SIZE);
If you are writing a binary file with an encoding other than the default character encoding of the operating system or if you want to write non-ASCII characters, you should the OutputStreamWriter class as shown below:
try // create a writer FileOutputStream fos = new FileOutputStream(new File("output.dat")); // set encoding to UTF_8 OutputStreamWriter writer = new OutputStreamWriter(fos, StandardCharsets.UTF_8); // write data to file writer.write("Hey, there!"); writer.write("\n"); writer.write("How are you doing?"); // flush remaining bytes writer.flush(); // close the writer writer.close(); > catch (IOException ex) ex.printStackTrace(); >
You can even wrap the OutputStreamWriter object in a BufferedWriter object to improve the performance by reducing the number of I/O operations performed:
try // create a writer FileOutputStream fos = new FileOutputStream(new File("output.dat")); // set encoding to UTF_8 OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8); // wrap in `BufferedWriter` BufferedWriter writer = new BufferedWriter(osw); // write data to file writer.write("Hey, there!"); writer.newLine(); writer.write("How are you doing?"); // flush remaining bytes writer.flush(); // close the writer writer.close(); > catch (IOException ex) ex.printStackTrace(); >
For more file read and write examples, check out the Reading and Writing Files in Java tutorial. ✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.
You might also like.
How to Read and Write Binary Files in Java
In this Java File IO tutorial, we show you how to read and write binary files using both legacy File I/O API and new File I/O API (NIO). The legacy API (classes in the java.io.* package) is perfect for manipulating low-level binary I/O operations such as reading and writing exactly one byte at a time, whereas the NIO API (classes in the java.nio.* package) is more convenient for reading and writing the whole file at once, and of course, faster than the old File I/O API.
1. Understanding Byte Streams
We use byte streams to read and write data in binary format, exactly 8-bit bytes. All byte stream classes are descended from the abstract classes InputStream and OutputStream . The following class diagram depicts the main classes in the legacy File I/O API that are designed for working with binary files:
You can notice that these classes implement the AutoCloseable interface, which means that we can use the try-with-resources structure to close these streams automatically.
At the top of the hierarchy, the abstract class InputStream defines two primary methods for reading bytes from an input stream:
- read() : reads one byte of data, returns the byte as an integer value. Return -1 if the end of the file is reached.
- read(byte[]) : reads a chunk of bytes to the specified byte array, up to the size of the array. This method returns -1 if there’s no more data or the end of the file is reached.
Similarly, the abstract class OutputStream defines two primary methods for writing bytes to an output stream:
- write(int) : writes the specified byte to the output stream.
- write(byte[]) : writes the specified array of bytes to the output stream.
Moving down, the implementation classes FileInputStream and FileOutputStream are for reading and writing streams of raw bytes, one or multiple bytes at a time. Whereas the BufferedInputStream and BufferedOutputStream are more efficient by buffering the input stream and output stream to reduce the number of calls to the native API.
Now, let’s see some code examples.
2. Reading and Writing Binary Files Using FileInputStream and FileOutputStream
The following examples use the FileInputStream and FileOutputStream classes to perform low level binary I/O.
This program copies one file to another, one byte at a time. The source file and destination file are provided from command line’s arguments:
import java.io.*; /** * Copy one file to another using low level byte streams, one byte at a time. * @author www.codejava.net */ public class CopyFiles < public static void main(String[] args) < if (args.length < 2) < System.out.println("Please provide input and output files"); System.exit(0); >String inputFile = args[0]; String outputFile = args[1]; try ( InputStream inputStream = new FileInputStream(inputFile); OutputStream outputStream = new FileOutputStream(outputFile); ) < int byteRead = -1; while ((byteRead = inputStream.read()) != -1) < outputStream.write(byteRead); >> catch (IOException ex) < ex.printStackTrace(); >> >
java CopyFiles Project.zip Project1(1).zip
And the following program runs faster because it reads the whole input file into an array of bytes and then write the whole array of bytes to the output file:
import java.io.*; /** * Copy one file to another using low level byte streams, * read and write a whole.at once. * @author www.codejava.net */ public class CopyFilesOne < public static void main(String[] args) < if (args.length < 2) < System.out.println("Please provide input and output files"); System.exit(0); >String inputFile = args[0]; String outputFile = args[1]; try ( InputStream inputStream = new FileInputStream(inputFile); OutputStream outputStream = new FileOutputStream(outputFile); ) < long fileSize = new File(inputFile).length(); byte[] allBytes = new byte[(int) fileSize]; int bytesRead = inputStream.read(allBytes); outputStream.write(allBytes, 0, bytesRead); >catch (IOException ex) < ex.printStackTrace(); >> >
And the following program runs much faster by copying a chunk of bytes at a time (exactly 4096 bytes at a time):
import java.io.*; /** * Copy one file to another using low level byte streams, 4KB at a time. * @author www.codejava.net */ public class CopyFilesChunk < private static final int BUFFER_SIZE = 4096; // 4KB public static void main(String[] args) < if (args.length < 2) < System.out.println("Please provide input and output files"); System.exit(0); >String inputFile = args[0]; String outputFile = args[1]; try ( InputStream inputStream = new FileInputStream(inputFile); OutputStream outputStream = new FileOutputStream(outputFile); ) < byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead = -1; while ((bytesRead = inputStream.read(buffer)) != -1) < outputStream.write(buffer, 0, bytesRead); >> catch (IOException ex) < ex.printStackTrace(); >> >
The following program reads the first 8 bytes of a file to identify if it is a PNG image format or not:
import java.io.*; /** * This program checks whether a file is of PNG image format or not, * by analysing its first 8 bytes. * @author www.codejava.net */ public class CheckPNG < private static int[] pngSignature = ; public static void main(String[] args) < if (args.length < 1) < System.out.println("Please provide the input file"); System.exit(0); >String inputFile = args[0]; try ( InputStream inputStream = new FileInputStream(inputFile); ) < int[] headerBytes = new int[8]; boolean isPNG = true; for (int i = 0; i < 8; i++) < headerBytes[i] = inputStream.read(); if (headerBytes[i] != pngSignature[i]) < isPNG = false; break; >> System.out.println("Is PNG file? " + isPNG); > catch (IOException ex) < ex.printStackTrace(); >> >
As you can see, using FileInputStream and FileOutputStream is really good for low level binary I/O such as analyzing a file or even create your own file format.
3. Reading and Writing Binary Files Using BufferedInputStream and BufferedOutputStream
Using BufferedInputStream and BufferedOutputStream is as same as FileInputStream and FileOutputStream . The only difference is that a buffered stream uses an array of byte internally to buffer the input and output to reduce the number of calls to the native API, hence increasing IO performance.
By default, both BufferedInputStream and BufferedOutputStream has an internal buffer of 8192 bytes (8KB), but we can specify a custom buffer size at initialization.
All the above examples can be re-written using buffered streams just by changing the instantiation of the streams. Here’s an example:
try ( InputStream inputStream = new BufferedInputStream(new FileInputStream(inputFile)); OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outputFile)); ) < byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead = -1; while ((bytesRead = inputStream.read(buffer)) != -1) < outputStream.write(buffer, 0, bytesRead); >> catch (IOException ex)
int bufferSize = 16384; // 16KB buffer size InputStream inputStream = new BufferedInputStream(new FileInputStream(inputFile), bufferSize); OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outputFile), bufferSize);
4. Reading and Writing Binary Files Using New File I/O API (NIO)
The utility class Files in the java.nio.file package provides the following methods for reading and writing binary data:
- readAllBytes(Path path) : reads all bytes from a file and returns an array of bytes. This method is intended for reading small files, not large ones.
- write(Path path, byte[] bytes, OpenOption. options) : writes an array of bytes to a file with some useful options like CREATE, TRUNCATE_EXISTING, WRITE and APPEND.
Let’s see an example. The files copy program above can be re-written using NIO API like this:
import java.io.*; import java.nio.file.*; /** * Copy one file to another using low level byte streams, one byte at a time. * @author www.codejava.net */ public class CopyFilesNIO < public static void main(String[] args) < if (args.length < 2) < System.out.println("Please provide input and output files"); System.exit(0); >String inputFile = args[0]; String outputFile = args[1]; try < long start = System.currentTimeMillis(); byte[] allBytes = Files.readAllBytes(Paths.get(inputFile)); Files.write(Paths.get(outputFile), allBytes); long end = System.currentTimeMillis(); System.out.println("Copied in " + (end - start) + " ms"); >catch (IOException ex) < ex.printStackTrace(); >> >
Try to run this program and compare the time with the ones using legacy File I/O (on big files) you will see NIO performs much faster.
API References:
Related File IO Tutorials:
Other Java File IO Tutorials:
About the Author:
Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on Facebook and watch his Java videos you YouTube.