0

I'm working on a project which, in part, displays all the files in a directory in a JTable, including sub-directories. Users can double-click the sub-directories to update the table with that new directory's content. However, I've run into a problem.

My lists of files are generated with file.listFiles(), which pulls up everything: hidden files, locked files, OS files, the whole kit and caboodle, and I don't have access to all of them. For example, I don't have permission to read/write in "C:\Users\user\Cookies\" or "C:\ProgramData\ApplicationData\". That's ok though, this isn't a question about getting access to these. Instead, I don't want the program to display a directory it can't open. However, the directories I don't have access to and the directories I do are behaving almost exactly the same, which is making it very difficult to filter them out.

The only difference in behavior I've found is if I call listFiles() on a locked directory, it returns null. Here's the block of code I'm using as a filter:

for(File file : folder.listFiles())
    if(!(file.isDirectory() && file.listFiles() == null))
        strings.add(file.getName());

Where 'folder' is the directory I'm looking inside and 'strings' is a list of names of the files in that directory. The idea is a file only gets loaded into the list if it's a file or directory I'm allowed to edit. The filtering aspect works, but there are some directories which contain hundreds of sub-directories, each of which contains hundreds more files, and since listFiles() is O(n), this isn't a feasible solution (list() isn't any better either).

However, file.isHidden() returns false

canWrite()/canRead()/canExecute() return true

getPath() returns the same as getAbsolutePath() and getCanonicalPath()

createNewFile() returns false for everything, even directories I know are ok. Plus, that's a solution I'd really like to avoid even if that worked.

Is there some method or implementation I just don't know to help me see if this directory is accessible without needing to parse through all of its contents?

(I'm running Windows 7 Professional and I'm using Eclipse Mars 4.5.2, and all instances of File are java.io.File).

Lord Farquaad
  • 712
  • 1
  • 12
  • 33
  • If you want to do accurate filesystem objects manipulations, forget `File` and use JSR 203 instead. More details [here](http://java7fs.wikia.com/wiki/Why_File_sucks). – fge Aug 01 '16 at 19:30
  • I'm 3500 lines in. It's a bit late for that. But thanks though, I'll definitely check that out in my next project. – Lord Farquaad Aug 01 '16 at 19:34
  • The problem is that, well, you have to. `File` can't do it. Period... – fge Aug 01 '16 at 19:34
  • That's the most devastating piece of news I've heard in quite some time – Lord Farquaad Aug 01 '16 at 19:35
  • JSR 203 can, which is why I included the link above (which I have written). I will write a detailed answer below, but most of it will be a repeat of this link anyway. Also, you have to defined "protected": user can't read/write? OS has builtin restrictions enforced? Etc etc. – fge Aug 01 '16 at 19:37
  • Wow, I've actually already read your article (Because, yeah, I'm pretty let down with File too). Small world. I suppose it wouldn't be too bad to let JSR take over for this part, it's not like I'd have to rewrite the whole thing. Thanks a bunch for pointing me in the right direction, you don't need to write out an example if you don't want, I don't mind working that out on my own. If you want to anyway for future people, I'll check your answer though. Oh! And I think it's builtin restrictions? It's the files you get when you uncheck "Hide protected operating system files" in Windows Explorer. – Lord Farquaad Aug 01 '16 at 19:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/118846/discussion-between-fge-and-lordfarquaad). – fge Aug 01 '16 at 19:47

2 Answers2

4

The problem you have is that you are dealing with File. By all accounts, in 2016, and, in fact, since 2011 (when Java 7 came out), it has been superseded by JSR 203.

Now, what is JSR 203? It is a totally new API to deal with anything file systems and file system objects; and it extend the definition of a "file system" to include what you find on your local machine (the so called "default filesystem" by the JDK) and other file systems which you may use.

Sample page on how to use it: here

Among the many advantages of this API is that it grants access to metadata which you could not access before; for instance, you specifically mention the case, in a comment, that you want to know which files Windows considers as "system files".

This is how you can do it:

// get the path
final Path path = Paths.get(...);
// get the attributes
final DosAttributes attrs = Files.readAttributes(path, DosFileAttributes.class);
// Is this file a "system file"?
final boolean isSystem = attrs.isSystem();

Now, what is Paths.get()? As mentioned previously, the API gives you access to more than one filesystem at a time; a class called FileSystems gives access to all file systems visible by the JDK (including creating new filesystems), and the default file system, which always exists, is given by FileSystems.getDefault().

A FileSystem instance also gives you access to a Path using FileSystem#getPath.

Combine this and you get that those two are equivalent:

Paths.get(a, b, ...)
FileSystems.getDefault().getPath(a, b, ...)

About exceptions: File handles them very poorly. Just two examples:

  • File#createNewFile will return false if the file cannot be created;
  • File#listFiles will return null if the contents of the directory pointed by the File object cannot be read for whatever reason.

JSR 203 has none of these drawbacks, and does even more. Let us take the two equivalent methods:

These methods, and others, have a fundamental difference in behaviour: in the event of a failure, they will throw an exception.

And what is more, you can differentiate what exception this is:

  • if it is a FileSystemException or derivative, the error is at the filesystem level (for instance, "access denied" is an AccessDeniedException);
  • if is is an IOException, then the problem is more fundamental.

This answer cannot contain each and every use case of JSR 203; this API is vast, very complete, although not without flaws, but it is infinitely better than what File has to offer in any case.

fge
  • 119,121
  • 33
  • 254
  • 329
  • Just to be sure, using Path is "the same" as having a File object but better? – Meik Vtune Aug 01 '16 at 19:59
  • @MeikVtune not quite; while metadata from a `File` was within `File` itself, with the new API, you need to query other parts of the API; and the `Files` utility class is the main entry point to it. This will be enough in 99+% of cases, mind you, but some very specific uses may require that you use other parts of the API as well – fge Aug 01 '16 at 20:02
  • The [here](http://java7fs.wikia.com/wiki/Using_the_java.nio.file_API) link is dead. Do you have a replacement link or could you put a little snippet how to use it in the answer? – Ted Lyngmo Nov 19 '21 at 08:54
0

I faced the very same problem with paths like C://users/myuser/cookies.

I already used JSR203, so the above answer kind of didn't help me. In my case the important attribute of those files was the hidden one.

I ended up using the FileSystemview, which excluded those files as I wanted.

File[] files = FileSystemView.getFileSystemView().getFiles(new File(strHomeDirectory), !showHidden);
MoxxiManagarm
  • 8,735
  • 3
  • 14
  • 43