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.
Reading and Writing Binary Files
To open a file for reading, you can use the newInputStream(Path, OpenOption. ) method. This method returns an unbuffered input stream for reading bytes from the file.
Path file = . ; try (InputStream in = Files.newInputStream(file); BufferedReader reader = new BufferedReader(new InputStreamReader(in))) < String line = null; while ((line = reader.readLine()) != null) < System.out.println(line); >> catch (IOException x)
Creating and Writing a File by Using Stream I/O
You can create a file, append to a file, or write to a file by using the newOutputStream(Path, OpenOption. ) method. This method opens or creates a file for writing bytes and returns an unbuffered output stream.
The method takes an optional OpenOption parameter. If no open options are specified, and the file does not exist, a new file is created. If the file exists, it is truncated. This option is equivalent to invoking the method with the CREATE and TRUNCATE_EXISTING options.
The following example opens a log file. If the file does not exist, it is created. If the file exists, it is opened for appending.
import static java.nio.file.StandardOpenOption.*; import java.nio.file.*; import java.io.*; public class LogFileTest < public static void main(String[] args) < // Convert the string to a // byte array. String s = "Hello World! "; byte data[] = s.getBytes(); Path p = Paths.get("./logfile.txt"); try (OutputStream out = new BufferedOutputStream( Files.newOutputStream(p, CREATE, APPEND))) < out.write(data, 0, data.length); >catch (IOException x) < System.err.println(x); >> >
Reading and Writing Files by Using Channel I/O
While stream I/O reads a character at a time, channel I/O reads a buffer at a time. The ByteChannel interface provides basic read and write functionality. A SeekableByteChannel is a ByteChannel that has the capability to maintain a position in the channel and to change that position. A SeekableByteChannel also supports truncating the file associated with the channel and querying the file for its size.
The capability to move to different points in the file and then read from or write to that location makes random access of a file possible. See the section Random Access Files for more information.
There are two methods for reading and writing channel I/O.
Note: The newByteChannel() methods return an instance of a SeekableByteChannel . With a default file system, you can cast this seekable byte channel to a FileChannel providing access to more advanced features such mapping a region of the file directly into memory for faster access, locking a region of the file so other processes cannot access it, or reading and writing bytes from an absolute position without affecting the channel’s current position.
Both newByteChannel() methods enable you to specify a list of OpenOption options. The same open options used by the newOutputStream() methods are supported, in addition to one more option: READ is required because the SeekableByteChannel supports both reading and writing.
Specifying READ opens the channel for reading. Specifying WRITE or APPEND opens the channel for writing. If none of these options are specified, then the channel is opened for reading.
The following code snippet reads a file and prints it to standard output:
public static void readFile(Path path) throws IOException < // Files.newByteChannel() defaults to StandardOpenOption.READ try (SeekableByteChannel sbc = Files.newByteChannel(path)) < final int BUFFER_CAPACITY = 10; ByteBuffer buf = ByteBuffer.allocate(BUFFER_CAPACITY); // Read the bytes with the proper encoding for this platform. If // you skip this step, you might see foreign or illegible // characters. String encoding = System.getProperty("file.encoding"); while (sbc.read(buf) >0) < buf.flip(); System.out.print(Charset.forName(encoding).decode(buf)); buf.clear(); >> >
The following example, written for UNIX and other POSIX file systems, creates a log file with a specific set of file permissions. This code creates a log file or appends to the log file if it already exists. The log file is created with read/write permissions for owner and read only permissions for group.
import static java.nio.file.StandardOpenOption.*; import java.nio.*; import java.nio.channels.*; import java.nio.file.*; import java.nio.file.attribute.*; import java.io.*; import java.util.*; public class LogFilePermissionsTest < public static void main(String[] args) < // Create the set of options for appending to the file. Setoptions = new HashSet(); options.add(APPEND); options.add(CREATE); // Create the custom permissions attribute. Set perms = PosixFilePermissions.fromString("rw-r-----"); FileAttribute attr = PosixFilePermissions.asFileAttribute(perms); // Convert the string to a ByteBuffer. String s = "Hello World! "; byte data[] = s.getBytes(); ByteBuffer bb = ByteBuffer.wrap(data); Path file = Paths.get("./permissions.log"); try (SeekableByteChannel sbc = Files.newByteChannel(file, options, attr)) < sbc.write(bb); >catch (IOException x) < System.out.println("Exception thrown: " + x); >> >