【问题标题】:AccessDeniedException after folder deleted文件夹删除后的 AccessDeniedException
【发布时间】:2021-04-13 15:59:19
【问题描述】:

我运行测试用例并将执行期间创建的文件保存在“执行”目录中(每个测试的文件在单独的子目录中) 在套件开始时我想清理这个文件夹

所以在 @BeforeSuite 方法中,我从“执行”目录中读取所有项目:

public static List<File> getRecursivelyAllFilesFromDirectory(String directory) throws IOException {
    List<File> files = new ArrayList<>();
    files.addAll(readAllFilesFromDirectory(directory));

    List<File> subDirs = readSubdirectories(directory);

    subDirs.forEach(dir -> {
        try {
            files.addAll(readAllFilesFromDirectory(dir.getPath()));
            files.add(dir);
        } catch (IOException e) {
            e.printStackTrace();
        }
    });

    return files;
}

然后我想删除所有内容

public static void cleanExecutionDirectory() throws IOException {
    LOGGER.info("Cleaning execution directory...");
    String executionDir = getExecutionDir();
    List<File> files = FileUtils.getRecursivelyAllFilesFromDirectory(executionDir);
    for (File file : files) {
        file.delete();
    }
    LOGGER.info(String.format("%d items deleted", files.size()));
}

但是接下来在 @BeforeScenario 我尝试为新的执行创建具有相同名称的子文件夹

public static void setTestCaseDir(String testCaseName) throws IOException {
    testCaseDir = testCaseName.split(StringUtils.SPACE)[0];
    String executionDir = getExecutionDir();
    Path testCaseDirPath = Paths.get(executionDir, testCaseDir);
    boolean isSubDir = readSubdirectories(executionDir)
            .stream()
            .filter(subDir -> subDir.getPath().equals(testCaseDirPath))
            .findFirst()
            .isPresent();
    if (!isSubDir) {
        Files.createDirectory(testCaseDirPath);
    }
    testCaseDir = testCaseDirPath.toString();
}

我收到异常:

java.nio.file.AccessDeniedException: D:\...\src\test\resources\execution\TC01

at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:83)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.createDirectory(WindowsFileSystemProvider.java:504)
at java.nio.file.Files.createDirectory(Files.java:674)
at utils.ExecutionUtils.setTestCaseDir(ExecutionUtils.java:56)
at integration.steps.StepDefs.beforeScenario(StepDefs.java:29)

尽管 setTestCaseDir 方法中的 readSubdirectories() 返回空列表,但还是会发生这种情况。 我在文件资源管理器中看到这个子目录是可见的,但我也无法访问它们。 当此执行由于此异常而失败时,此子文件夹将被解锁并消失。

什么进程可能会锁定这个子文件夹以及如何解决这个问题?

【问题讨论】:

  • 你不显示readSubdirectories,这是使用目录流吗?
  • 这是完整的堆栈跟踪吗?这里少了很多。显示getExecutionDir()readSubdirectories()readAllFilesFromDirectory()以及出错时相关变量的值。
  • readSubdirs() 返回文件是深度优先还是广度优先?如果没有看到我之前评论中列出的方法,我们可能无法帮助您。

标签: java file exception delete-file access-denied


【解决方案1】:

请注意,对层次结构中的文件进行任何挥之不去的未关闭操作都可能会阻止删除工作 - 因此请检查在这些目录上工作的其他测试并为目录流添加 try-with-resources (Files list / newDirectoryStream) 和 @ 987654322@ 输入/输出流(在 Windows 上也是 MappedByteBuffer)。

一旦修复,FileVisitorFiles.walkFileTree 提供了一种更可靠的删除树的方法,并且在大型目录树上它比递归 File.list 更快:

public static void main(String[] args) throws IOException {
    var paths = Arrays.stream(args).map(Path::of).collect(Collectors.toList());

    FileVisitor<Path> deleteTree = new FileVisitor<>() {
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException  {
            return FileVisitResult.CONTINUE;
        }
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            System.out.println("Delete FILE "+file);
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }
        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
            throw exc;
        }
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
            System.out.println("Delete DIR "+dir);
            Files.delete(dir);
            return FileVisitResult.CONTINUE;
        }
    };

    for (Path p : paths) {
        Files.walkFileTree(p, deleteTree);
    }
}

【讨论】:

    【解决方案2】:

    受@DuncG 启发,我使用 NIO2 和 Java8 解决了这个问题

    public static void cleanExecutionDirectory() throws IOException {
        LOGGER.info("Cleaning execution directory...");
        File executionDir = new File(getExecutionDir());
        if (executionDir.exists()) {
            Path executionDirPath = Paths.get(getExecutionDir());
            Files.walk(executionDirPath)
                    .sorted(Comparator.reverseOrder())
                    .forEach(path -> {
                        try {
                            Files.delete(path);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    });
            LOGGER.info(String.format("Items deleted"));
        }
        executionDir.mkdir();
    }
    

    【讨论】:

      猜你喜欢
      • 2022-09-27
      • 2013-11-23
      • 2016-06-30
      • 2021-03-21
      • 1970-01-01
      • 2021-07-07
      • 2020-07-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多