I'm using Java 17 on Windows 10 with NTFS. There is a file A:\foo.bar
that shows up in a Java Files.list()
operation, but that when I try to read it using Java, it throws a java.nio.file.FileSystemException
:
A:\foo.bar: The process cannot access the file because it is being used by another process
That's fine. There is another low-level process which has locked the file. When I turn off that other process, Java can access the file just fine. In fact even Robocopy, when trying to access this file, will skip the file (actually it will appear that Robocopy has copied the file, but it hasn't). So no mystery so far—another process is locking the file for exclusive access.
But here's the strange part. For the most part the file appears normal to Java:
- As I mentioned the file
A:\foo.bar
shows up in aFiles.list()
ofA:\
. - If I call
Files.isRegularFile(fooBarFile)
, it returnstrue
as expected. - If I call
Files.isReadable(fooBarFile)
, it turnsfalse
as I might expect (and which is useful in this case). - If I call
Files.readAttributes(fooBarFile, "*")
I see the attributes (timestamps, etc.). - If I call
Files.readAttributes(fooBarFile, DosFileAttributes.class)
it returns the DOS attributes.
But if I call Files.exists(fooBarFile)
it returns false
! So it would appear that a file that is locked for exclusive access by another process will return false
for exists()
, which to me doesn't seem to follow the semantics of the exists()
method as explained in its API.
As it is, it does seem useful to see if a file is not accessible by checking to see if exists()
returns false
yet isRegularFile()
returns true
; nevertheless that was unexpected and seems to be undocumented. Is this expected behavior? Is it documented? Does it work the same on other platforms, e.g. Linux?
Finally I note that Files.notExists(fooBarFile)
returns false
as well, so Java is not saying that the file is nonexistent, merely that it does not exist. Hmmm … the only way I can make that make sense is if exists()
means "accessible", but the API contract for exists()
does not talk about accessibility. The notExists()
documentation adds:
Note that this method is not the complement of the exists method. Where it is not possible to determine if a file exists or not then both methods return false.
That doesn't seem to apply to this situation either. So although this behavior is useful, it is unexpected, doesn't seem to be documented, and therefore I'm hesitant about relying too much on it. Can anyone provide more information or better yet authoritative documentation?
Update: A similar thing seems to happen with unreadable directories. For example the A:\System Volume Information
directory is marked as "hidden" and "read-only" on Windows. It similarly throws a java.nio.file.FileSystemException
exception if you try to access it. But Files.exists()
returns false
, even though Files.isDirectory()
returns true
! In fact it behaves exactly as the bullet points above, except that isDirectory()
returns true
instead of isRegularFile()
.
Thus it seems like Files.exists()
is duplicating Files.isReadable()
(at least on OpenJDK 17 on Windows), even though that behavior doesn't seem to follow the Files.exists()
API contract. Is this a JDK bug?