Check does file exist java.nio

658 Views Asked by At

I'm trying to check does file exist but it doesn't work.

FileSystem fs = FileSystems.getDefault();
Path p = fs.getPath(fileName);

if(!Files.exists(p)) {
    create(fileName);
} else {
    throw new ConflictException(String.format("File already exist."));
}

The problem is that even the file exist with same fileName it goes inside if statement and goes to create method and when it came to part to create file then it returns exception that file already exists. What could be the problem and possible solution to check does file/directory exists if I'm using FileSystem?

1

There are 1 best solutions below

3
On

You're doing it wrong.

The general principle when working in environments subject to external change, such as file systems, you just cannot do check-and-act. That entire principle is broken in such an environment, and you're doing it here:

You check if the file exists, and then depending on the result of that, you choose an action. That's check-and-act and doesn't work.

After all, what if the 'answer' to your check changes in between the check and the act? It doesn't even have to be another thread within your own VM, it can be another process. You can't synchronize on anything to get this job done 'safely' either.

No, the right principle is act-then-check. Do the operation 'make this file but only if it is not already there', atomically, and deal with the fallout, that is, deal with the error afterwards if the file already existed.

Java's nio has support for this, fortunately (the old File API does not, don't use that). Lastly, there is no need to go via the FileSystem stuff, not as long as you are using the default filesystem. However, if that was just there for the purposes of simplifying the question, this works just as well with a custom filesystem:

Path p = Paths.get(fileName);

try {
    try (var out = Files.newOutputStream(p, StandardOpenOption.CREATE_NEW)) {
       // write your file here
    }
} catch (FileAlreadyExistsException e) {
    throw new ConflictException(String.format("File already exists", e);
}
// CREATE_NEW is the magic voodoo here: That tells java:
// do this ONLY if you make a new file, otherwise don't do it, atomically.

though note that FAEException is fine as is, so I'm not sure you should neccessarily wrap that into a conflictexception - that only makes sense if this API has abstracted away the notion that you are doing this thing to the filesystem (you did not include a method name or javadoc in your paste, so I can't tell).

If you don't need to write anything to the file, you don't need newOutputStream, you can just go with:

Path p = Paths.get(fileName);

try {
    Files.createFile(p);
} catch (FileAlreadyExistsException e) {
    throw new ConflictException(String.format("File already exists", e);
}
// Files.createFile implies CREATE_NEW already; it either makes
// the file and returns, or doesn't and throws FAEEx.