You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java NIO递归重命名含文件文件夹遇AccessDeniedException求助

Fixing AccessDeniedException When Renaming Directories with Java NIO Files.walkFileTree

Hey there, let's break down why you're hitting that AccessDeniedException and how to fix it.

The Root Cause

On Windows (which your path structure indicates you're using), when you use Files.walkFileTree, the file system traversal context keeps a handle open to each directory even during the postVisitDirectory phase. Trying to rename the directory while this handle is still held will trigger an access denied error—Windows locks directories that are actively being accessed by a process. Your current approach renames directories mid-traversal, which conflicts with this locking behavior.

The Solution: Collect First, Rename Later

Instead of renaming files/directories while traversing the tree, we'll:

  1. Traverse the entire directory structure and collect all paths that need renaming.
  2. Sort the directory paths so we rename deepest subdirectories first, then work our way up to parent directories. This ensures we don't try to rename a parent directory before its children are already renamed.
  3. Rename all eligible files first, then process the sorted directories.

Modified Code

Here's the adjusted version of your code that implements this approach:

package com.din.pach;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class FileNio {
    // Lists to hold paths that need renaming
    private static final List<Path> filesToRename = new ArrayList<>();
    private static final List<Path> dirsToRename = new ArrayList<>();
    private static final String PREFIX = "POPCORN-";

    public static void main(String[] args) throws IOException {
        Path sourcePath = Paths.get("D:\\root\\");
        
        // First pass: collect all files/dirs that need renaming
        Files.walkFileTree(sourcePath, new SimpleFileVisitor<>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                String fileName = file.getFileName().toString();
                if (fileName.startsWith(PREFIX)) {
                    filesToRename.add(file);
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
                String dirName = dir.getFileName().toString();
                if (dirName.startsWith(PREFIX)) {
                    dirsToRename.add(dir);
                }
                return FileVisitResult.CONTINUE;
            }
        });

        // Rename files first
        for (Path file : filesToRename) {
            renamePath(file);
        }

        // Sort directories by depth (deepest first)
        dirsToRename.sort(Comparator.comparingInt(path -> path.getNameCount()).reversed());
        
        // Rename directories from deepest to shallowest
        for (Path dir : dirsToRename) {
            renamePath(dir);
        }
    }

    private static void renamePath(Path path) throws IOException {
        String originalName = path.getFileName().toString();
        String newName = originalName.replaceFirst(PREFIX, "");
        Path newPath = path.resolveSibling(newName);
        
        // Use REPLACE_EXISTING to handle any existing files/dirs with the target name
        Files.move(path, newPath, StandardCopyOption.REPLACE_EXISTING);
        System.out.printf("Renamed: %s -> %s%n", path, newPath);
    }
}

Key Changes Explained

  • Separate Collection Phase: We first gather all paths that need renaming without modifying anything during traversal. This ensures the file system traverser can complete its work without interference, releasing all directory handles.
  • Directory Sorting: By sorting directories by their depth (reversed), we guarantee that we rename subdirectories before their parent directories. This avoids any issues where a parent directory rename would break references to unprocessed children.
  • Simplified Rename Logic: The renamePath method works for both files and directories, reducing code duplication.

Additional Notes

  • Make sure you're running the program with administrative privileges if the D:\root directory is in a protected location (though your error suggests permissions aren't the core issue here).
  • The SimpleFileVisitor is used instead of implementing all FileVisitor methods, which cleans up the code.

内容的提问来源于stack exchange,提问作者Dinesh Ravi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:52:37