18

I am trying to determine if a file exists in a network folder:

// File name is "\\QWERTY\folder\dir\A123456.TXT"
Path path = Paths.get("\\\\QWERTY\\folder\\dir\\A123456.TXT")

Using NIO Files:

Files.exists(path) == false

Using File:

path.toFile().exists() == true

Using File seems to be the correct one according to our tests. Why does File work better than Files?

So, which is it? Can't be both!

But wait, there is also Files.notExists(path).

When the network share file actually exists

Files.exists(path): false
Files.notExists(path): false
path.toFile().exists(): true

When the network share file actually does not exist

Files.exists(path): false
Files.notExists(path): true
path.toFile().exists(): false

Another equally insane way of looking at the three results above

boolean exists = Files.exists(path) || !Files.notExists(path)
boolean notExists = Files.notExists(path) || !Files.exists(path)
boolean oldFashionedExists = path.toFile().exists()

:smileyFace:

Environment and Comments

The program is running on a Windows 8.1 Pro 32 bit machine (OS and machine) and checking on a network share from a Windows 2008 R2 (32 bit) machine.

To determine that Files.exists was failed, I installed a WatchService to monitor the folder and saw that the file did exist when Files.exists was checking. I then logged as both methods and found File.exists to be the correct one.

Now, in my code I have the check as Files.exists(path) || path.toFile().exists().

Kinda seems stupid to have to do both. Probably could just get away with the later. Just trying to give the engineers over at Oracle the benefit of the doubt, but the whole thing is rather silly that they report different.

Also, I don't care if 'exists' is immediately outdated. I just want to know if the file exists at the instant that we are checking. I've never come across this -- we just spent 30 hours between me and another developer trying to figure out why our programs are not interfacing because of this 'feature'.

Meditate on this a while

File.exists(): Returns true if and only if the file or directory denoted by this abstract pathname exists; false otherwise.

Files.exists(): Returns true if the file exists; false if the file does not exist or its existence cannot be determined.

That cracks me up! "if and only if the file or directory denoted by this abstract pathname exists; false otherwise" is at odds with "true if the file exists; false if the file does not exist or its existence cannot be determined"

So, how still can File.exists be true if "the existence cannot be determined"? Obviously, the existence can be (and is being) determined by File but not by Files.

Community
  • 1
  • 1
The Coordinator
  • 13,007
  • 11
  • 44
  • 73
  • `Fils.exists` documentation: `Note that the result of this method is immediately outdated. If this method indicates the file exists then there is no guarantee that a subsequence access will succeed. Care should be taken when using this method in security sensitive applications.`. This could be the issue, especially over a network. – user1803551 May 29 '15 at 02:46
  • 1
    @user1803551, I'm pretty certain that's true for the other one as well, there's no guarantee in _either_ case that someone won't delete the file between your check and attempted use. – paxdiablo May 29 '15 at 02:49
  • Can you try `Files.notExists` and see what result you get? – user1803551 May 29 '15 at 02:53
  • I don't care if it is immediately outdated. I just want to know if the file exists at the instant that we are checking. I've never come across this, We just spent 30 hours between me and another developer trying to figure out what our programs are not interfacing because of this 'feature'. – The Coordinator May 29 '15 at 02:53
  • As I asked above, if you use `Files.notExists` and it returns `true` then you have a conflict, if `false` then it is an access problem and you'll have to compare them with a local file. – user1803551 May 29 '15 at 03:06
  • Just to entertain everyone, I am going to mock it and post the result. So , now I will be checking two Files methods and one File method to ascertain a file exists. Heck ... I could even open a FileInputStream and check for an exception .. which is also rather sillyness. – The Coordinator May 29 '15 at 03:09
  • 1
    Beware of UNC paths, had a lot of trouble with those, especially on Windows 8 – MadProgrammer May 29 '15 at 03:12
  • @SaintHill Does calling `Files#deleteIfExists` throws an IOException or does it delete the file ? – Jean-François Savard May 29 '15 at 03:20
  • @user1803551 Files.notExists test added to question – The Coordinator May 29 '15 at 03:41
  • Good. What would be the results for a local file if it exists? – user1803551 May 29 '15 at 03:44
  • Quite apart from the question of the logical criteria used by each of the methods for determining existence, is what the methods themselves do to perform the check. Both result on native code. Is it the generally the same native code or is the nio version somehow more robust than the earlier io version – Steve Cohen Jan 07 '16 at 14:55
  • I'll let someone else look into that or answer that. Beyond me. – The Coordinator Jan 08 '16 at 19:47
  • 1
    *"So, how still can File.exists be true if "the existence cannot be determined"? Obviously, the existence can be (and is being) determined by File but not by Files."* The File.exists() method only works with `File` instances, which denote resources on the filesystem. `Files.exists(Path)` works with `Path` instances, which can capture (depending on the available FileSystemProviders) things that are not in the filesystem. – Joshua Taylor Feb 02 '21 at 17:26
  • That's one way of looking at it. – The Coordinator Feb 04 '21 at 00:26

2 Answers2

10

As to why there may be a difference between the two, contrast their documentation:

File.exists(): Returns true if and only if the file or directory denoted by this abstract pathname exists; false otherwise.

Files.exists(): Returns true if the file exists; false if the file does not exist or its existence cannot be determined.

That could possibly explain the difference between the two, perhaps the Files one is having troubles ascertaining the existence of the file.

For example, under Linux, it's possible to set up directory and file permissions in such a way that you can open a file that exists but cannot see that it exists (by taking away read permission on the directory the file is in while leaving the file permissions more open).

As per more of Oracle's documentation, Files.exists() only returns true if the file is verified to exist.

A return value of false does not mean it doesn't exist.

They suggest you use both exists() and notExists() to cover the three possibilities, something like:

if (Files.exists(fspec)) {
    System.out.println("It exists!");
else if (Files.notExists(fspec)) {
    System.out.println("It does not exist!");
else
    System.out.println("I have no idea!");

That covers the three possibilities of file state covered in that link above:

  • The file is verified to exist.
  • The file is verified to not exist.
  • The file's status is unknown. This result can occur when the program does not have access to the file.
Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    Actually, it is correct in my code, I just typed it wrong int he example. Thanks for spotting that. Corrected. – The Coordinator May 29 '15 at 02:49
  • 1
    Then why would `File#exists` return true ? The documentation specify that "true *if and only if* the file or directory denoted by this abstract pathname exists; " – Jean-François Savard May 29 '15 at 02:49
  • Hence my wording "which may or may not". – paxdiablo May 29 '15 at 02:51
  • @Jean-FrançoisSavard LOL. That's why I am posting the question. Now I am checking everything using 'Files.exists(path) || path.toFile().exists()' :) – The Coordinator May 29 '15 at 02:51
  • @Saint, since you've now changed the question to clarify the string you're using has the correct escapes, I've removed the initial section detailing why that was a problem. – paxdiablo May 29 '15 at 02:57
  • @paxdiablo So, what you are saying is that: exists = Files.exists(path) || !Files.notExists(path). And that also notExists = Files.notExists(path) || !Files.exists(path). :) – The Coordinator May 29 '15 at 03:50
  • You might want to use LinkOption.NOFOLLOW_LINKS to reduce the number of checks. – eckes May 29 '15 at 09:47
0

i had a same problem, but your hack doesn't helped me. When file was actually exist all methods returned me false:

Files.exists(path) = false, 
path.toFile().exists() = false, 
Files.notExists(path) = true, 
Files.exists(path) || path.toFile().exists() = false

But if at this moment in the explorer a network directory with this file was opened, then its existence was correctly handled

I solved this problem by creation of a new file in directory (then delete it):

Files.createFile(Paths.get(path.getParent().toString(), "test"));

After that command, apparently, Windows update information about folder

dparoli
  • 8,891
  • 1
  • 30
  • 38