So here's the thing: you're writing code that calls for creating a new file. But you don't want to overwrite an existing file of the same name if one exists.
What's the best way to make that happen?
That's an excellent question. And in this guide I offer an excellent answer.
Let's take a look at the problem first. Consider this code:
final String contents = "My contents"; final Path path = Paths.get("./", "contents.txt"); Files.write(path, contents.getBytes());
Run that code and check the root of where it ran. You'll see a text file called contents.txt with the words "My contents" inside.
(Please note: if you're using an IDE like Eclipse you may have to refresh the project to see the newly created file.)
Anyhoo, everything seems to be working.
Now change that top line to this:
final String contents = "My contents2";
Rerun the code and reexamine the text file.
You'll see that the old text file has been erased and the new file has the "My contents2" text in it.
But that could be catastrophic in a production environment.
You might overwrite a file that included some very important info.
So let's take a look at how to protect the existing file.
The Java NIO package includes an enum called StandardOpenOption. And that's what you'll use to protect the existing file.
Try running this:
final String contents = "My contents3"; final Path path = Paths.get("./", "contents.txt"); Files.write(path, contents.getBytes(), StandardOpenOption.CREATE_NEW);
Nope. You can't. You get an exception.
The strack trace looks like this:
java.nio.file.FileAlreadyExistsException: .\contents.txt at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:87) at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103) at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108) at java.base/sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:235) at java.base/java.nio.file.spi.FileSystemProvider.newOutputStream(FileSystemProvider.java:478) at java.base/java.nio.file.Files.newOutputStream(Files.java:220) at java.base/java.nio.file.Files.write(Files.java:3425)
So what happened?
That StandardOpenOption.CREATE_NEW option tells the JVM to throw an exception if the application tries to overwrite an existing file at the same location and with the same name.
Which is exactly what you want.
If you're trying to overwrite a file that you don't want to overwrite, that's an exception condition. You should treat it accordingly.
Catch that exception and handle it as you see fit. You'll probably want to include a "File already exists" message in the log.
But you might not need to take any further action. Since the file already exists, maybe you can just start appending text to it (think of something like a log).
What About APPEND?
Maybe you just read that last paragraph and thought to yourself: "Can't you use StandardOpenOption.APPEND to append text to something like a log file?"
Why yes. Yes you can.
But the problem with that is that the file must already exist. Otherwise, you'll get a NoSuchFileException.
In other words, APPEND won't create a new file for you.
Similarly, the WRITE option won't work (for the same reason) if the file doesn't exist.
By the way: if you use StandardOpenOption.CREATE instead of StandardOpenOption.CREATE_NEW, you will overwrite the file if it previously existed. So be careful with that one.
Wrapping It Up
Yes, there are other ways to avoid overwriting an existing file. A simple "if" check will also do the trick.
But the option I described here is my favorite. And I think it will help keep your code tight as well.
Photo by from