简体   繁体   中英

Files.walkFileTree throws access exception on some windows files

I am using Files.walkFileTree() on a Windows 10 Pro system, and prints an exception stackTrace on some files. I'm trying to figure out how to determine what files will throw this exception before it is thrown; so far none of the files that cause the error are interesting to me, but I want the program to be able to detect which files would throw the error before it's thrown.

code:

import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;

public class WindowsFilePlay extends SimpleFileVisitor<Path>
{
  public static void say(String s) { System.out.println(s); }
  public static void main(String[] args) throws IOException
  {
    WindowsFilePlay play = new WindowsFilePlay();
    play.go();
  }
  
  private void go() throws IOException
  {
    say("For running on a Windows system.");
    String dirString = "c:\\users\\ralph\\appdata\\local\\microsoft\\windowsapps\\";
    File dirFile = new File(dirString);
    Path dirPath = dirFile.toPath();
    
    Files.walkFileTree(dirPath, this);
    say("done.");
  }
  
  public FileVisitResult visitFile(Path p, BasicFileAttributes bfa) throws IOException
  {
    say("visiting " + p.toString());
    if (bfa.isSymbolicLink()) { say("It's a link"); } else { say("It's not a link"); }
    if (p.compareTo(p.toRealPath()) != 0) { say("not a junction"); }
    return FileVisitResult.CONTINUE;
  }

}

and console:

visiting c:\users\ralph\appdata\local\microsoft\windowsapps\GameBarElevatedFT_Alias.exe
It's not a link
Exception in thread "main" java.nio.file.FileSystemException: c:\users\ralph\appdata\local\microsoft\windowsapps\GameBarElevatedFT_Alias.exe: The file cannot be accessed by the system.

    at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
    at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
    at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
    at sun.nio.fs.WindowsLinkSupport.getFinalPath(WindowsLinkSupport.java:74)
    at sun.nio.fs.WindowsLinkSupport.getRealPath(WindowsLinkSupport.java:242)
    at sun.nio.fs.WindowsPath.toRealPath(WindowsPath.java:836)
    at sun.nio.fs.WindowsPath$WindowsPathWithAttributes.toRealPath(WindowsPath.java:138)
    at WindowsFilePlay.visitFile(WindowsFilePlay.java:32)
    at WindowsFilePlay.visitFile(WindowsFilePlay.java:1)
    at java.nio.file.Files.walkFileTree(Files.java:2670)
    at java.nio.file.Files.walkFileTree(Files.java:2742)
    at WindowsFilePlay.go(WindowsFilePlay.java:24)
    at WindowsFilePlay.main(WindowsFilePlay.java:15)

Some further information:

  • In the debugger, the class for the file attributes is sun.nio.fs.WindowsFileAttributes , an extension of BasicFileAttributes . I cannot just import WindowsFileAttributes; it's available to the runtime, but I don't know what version is used so I know what jar to put in my buildpath. So I cannot cast my BasicFileAttributes variable to WindowsFileAttributes and call its specific methods, unless I can get official assurance of which jar to use. I've noticed that there is a variable shown in the debugger for that class called reparseTag , which looks like a bit mask (value of 0x80000001b), but I don't know how to use it. The value is 0 for the few other files for which I've looked at it.

  • If I go to the DOS command line, these files are all there; they have 0 length, but other files on the disk with 0 length are processed without error. In DOS, they also appear in a list produced with dir/al , indicating (again) that they are symbolic links or reparse points or something. I'm confident this is related, but want to know how my program can detect that they cannot be treated like other files.

As stated in the document of Path#toRealPath

Throws:
...
SecurityException - In the case of the default provider, and a security manager is installed, its checkRead method is invoked to check read access to the file, and where this path is not absolute, its checkPropertyAccess method is invoked to check access to the system property user.dir

So to "detect which files would throw the error before it's thrown", just check if we can read the file before calling toRealPath .

    @Override
    public FileVisitResult visitFile(Path p, BasicFileAttributes bfa) throws IOException {
        say("visiting " + p.toString());
        if (bfa.isSymbolicLink()) {
            say("It's a link");
        } else {
            say("It's not a link");
        }
        if (!Files.isReadable(p)) {
            say("No right to read");
            return FileVisitResult.CONTINUE;
        }
        if (p.compareTo(p.toRealPath()) != 0) {
            say("not a junction");
        }
        return FileVisitResult.CONTINUE;
    }

Implement this method in your class next to visitFile:

            @Override
            public FileVisitResult visitFileFailed(Path file,
                    IOException exc) {
                System.err.println(exc);
                return FileVisitResult.CONTINUE;
            }

it handles the exceptions in SimpleFileVisitor. good luck.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM