【问题标题】:Files.walkFileTree throws access exception on some windows filesFiles.walkFileTree 在某些 windows 文件上引发访问异常
【发布时间】:2021-05-16 13:23:22
【问题描述】:

我在 Windows 10 Pro 系统上使用 Files.walkFileTree(),并在某些文件上打印异常 stackTrace。我试图弄清楚如何确定哪些文件会在抛出这个异常之前抛出它;到目前为止,我对导致错误的文件都没有兴趣,但我希望程序能够在错误被抛出之前检测到哪些文件会抛出错误。

代码:

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;
  }

}

和控制台:

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)

一些进一步的信息:

  • 在调试器中,文件属性的类是sun.nio.fs.WindowsFileAttributes,是BasicFileAttributes 的扩展名。我不能只导入 WindowsFileAttributes;它可用于运行时,但我不知道使用的是什么版本,所以我知道要在我的构建路径中放入什么 jar。所以我不能将我的 BasicFileAttributes 变量转换为 WindowsFileAttributes 并调用它的特定方法,除非我能得到官方保证使用哪个 jar。我注意到在该类的调试器中显示了一个名为reparseTag 的变量,它看起来像一个位掩码(值为 0x80000001b),但我不知道如何使用它。对于我查看过的其他几个文件,该值为 0。

  • 如果我转到DOS命令行,这些文件都在那里;它们的长度为 0,但磁盘上长度为 0 的其他文件被正确处理。在 DOS 中,它们也出现在使用dir/al 生成的列表中,表明(再次)它们是符号链接或重解析点或其他东西。我确信这是相关的,但想知道我的程序如何检测到它们不能像其他文件一样对待。

【问题讨论】:

    标签: java nio


    【解决方案1】:

    Path#toRealPath的文档所述

    投掷:
    ...
    SecurityException - 在默认提供程序的情况下,并且安装了安全管理器,调用其 checkRead 方法来检查对文件的读取访问权限,并且在此路径不是绝对路径的情况下,调用其 checkPropertyAccess 方法来检查对系统属性的访问权限用户目录

    所以要“在错误被抛出之前检测哪些文件会抛出错误”,只需在调用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;
        }
    

    【讨论】:

    • 似乎确实可以。你知道为什么吗?我将“阅读权”与“阅读权限”相关联,但我有权阅读此文件(afaik,至少“Windows 属性”显示的权限似乎表明我这样做)。 canRead() 是否涵盖除该特权之外的其他内容?
    • 另外,这将是一个恼人的性能问题。我有一个使用文件的程序版本,这个版本只使用路径。您是否知道任何方法来检查不依赖于为树中的每个文件创建文件对象的同一件事?编辑:我想我可以捕获他们的异常......
    • 对于第一条评论,我不是 Window 权限方面的专家,所以此刻我不能说太多。对于第二个,我更新为使用 Files.isReadable 以避免创建新的 File 对象。
    【解决方案2】:

    在你的访问文件旁边的类中实现这个方法:

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

    它处理 SimpleFileVisitor 中的异常。 祝你好运。

    【讨论】:

      猜你喜欢
      • 2013-08-10
      • 1970-01-01
      • 2018-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-08
      • 1970-01-01
      • 2011-05-18
      相关资源
      最近更新 更多