« Back to home

Java file I/O in 2014

There are lots of articles about file handling in Java. However, a lot of them seem to be out-of-date, given the advent of New IO (NIO) and the enhancements in Java 1.7. So, I sat down with the J2SE 7 JavaDoc, and put together this guide to how to do modern Java file I/O.

Step 0

Before you start dealing with file streams, see if Java NIO will do all the work for you. If you just need to read the lines of text from the file into memory, the Files class has a convenience method readAllLines() that will do the job as a one-liner.

If you need to do something more complicated, like obtain a file data stream you can parse to a parser, or parse files that might be bigger than available memory, then continue on…

Step 1

Decide whether you want file input, file output, or files you can both read and write.

If you want input or output, you also have to decide whether you want the files to be binary data or text.

Direction Type What to obtain How to obtain it
Input Binary InputStream Files.newInputStream(Path)
Input Text Reader Files.newBufferedReader(Path)
Output Binary OutputStream Files.newOutputStream(Path)
Output Text Writer Files.newBufferedWriter(Path)
Both Binary SeekableByteChannel Files.newByteChannel(Path, ...)

These are the NIO (new IO) methods for Java 1.7, and they all take Path objects as arguments. To get a Path object for a file:

Path path = FileSystems.getDefault().getPath("file.txt");

So your code would look like:

Path path = FileSystems.getDefault().getPath("file.txt");
Reader rdr = Files.newBufferedReader(path);

Note use of the abstract Reader class. The object will actually be a BufferedReader wrapping a FileReader wrapping an InputStream, but by using just the abstract type the code can be reused with any kind of reader.

You can also use the older Java I/O classes, which are your only choice for Java older than 1.7:

Direction Type What to obtain How to obtain it
Input Binary InputStream new InputStream(File)
Input Text Reader new BufferedReader(new InputStreamReader(new InputStream(File)))
Output Binary OutputStream new OutputStream(File)
Output Text Writer new BufferedWriter(new OutputStreamWriter(new OutputStream(File)))
Both Binary RandomAccessFile new RandomAccessFile(File)

For the older I/O classes, you need a File object. If you’re using a current version of Java, you can turn a Path object into a file object by calling its getFile() method. Or for any version of Java, you can construct a File object from a path string via its normal constructor.

As you might have noticed, getting Reader and Writer objects in old I/O is a pain. You might be tempted to use the FileReader and FileWriter classes, which make it convenient to go straight from a File to a Reader or Writer. Unfortunately, FileReader and FileWriter use the default character encoding for the Java platform; and sadly, that’s the legacy UTF-16 encoding, which is almost certainly not what you want unless you’re running Windows, and possibly not even then. Yes, you can change the encoding, but that requires a command-line argument to the Java VM at run time, which is ugly.

Step 2: Buffering

If you have a SeekableByteChannel or RandomAccessFile, it’s going to be binary and unbuffered and rather inconvenient, so you can stop reading at this point.

If you have a binary InputStream or OutputStream at this point, decide if you want buffering for your binary data.

If you do, wrap your Stream in a BufferedOutputStream or BufferedInputStream as appropriate.

If you have a text Reader or Writer, Java NIO will have automatically given you a buffered one. That’s the right decision, so I included the buffering in the old I/O table for step 1. You really don’t want to do unbuffered text I/O, particularly not with UTF-8 text.

Step 3: Convenience

If you have a Writer, you’ll probably want to wrap it in a PrintWriter to make life easier.

If you have a Reader, you’ll probably want to parse the input in some way. I recommend investigating the Scanner class.

Things to avoid

Here’s a list of some I/O classes to avoid using, why you should avoid them, and what to use instead:

Class Why you shouldn’t use it What to use instead
StringBufferInputStream It doesn’t convert characters properly. StringReader
LineNumberInputStream It doesn’t convert characters properly. LineNumberReader
FileReader It reads UTF-16. InputStreamReader
FileWriter It writes UTF-16. OutputStreamWriter