【问题标题】:How to rename the folders and subfolders including the files present in it recursively using Java NIO Files?如何使用 Java NIO Files 以递归方式重命名文件夹和子文件夹,包括其中存在的文件?
【发布时间】:2018-06-27 11:10:36
【问题描述】:

我无法重命名包含文件或子文件夹的文件夹。

我的文件夹结构是

D:
  root
      popcorn-folder1     
           popcorn-subfolder1   
               popcorn-subfile1
           popcorn-file1         
      popcorn-folder2 
           popcorn-subfolder2  
           popcorn-file2 

我的结果目录应该是

D:
  root
      folder1     
           subfolder1   
               subfile1
           file1         
      folder2 
           subfolder2  
           file2  

我尝试过的代码是

package com.din.pach;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;

public class FileNio {

public static void main(String[] args) throws IOException {

    Path sourcePath      = Paths.get("D:\\root\\");

    Files.walkFileTree(sourcePath, new FileVisitor<Path>() {
        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
            // System.out.println("pre visit dir:" + dir);
            //rename(dir);
            //renameFile(dir);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            //System.out.println("visit file: " + file);
            renameFile(file);
            System.out.println("====================================================================");
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
            //   System.out.println("visit file failed: " + file);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
            //  System.out.println("post visit directory: " + dir);
            renameDirectory(dir);
            return FileVisitResult.CONTINUE;
        }



    });



}

public static void renameFile(Path file) throws IOException {


    boolean isDirectory = Files.isDirectory(file);
    boolean isWritable = Files.isWritable(file);
    System.out.println("isDirectory-> "+isDirectory);
    System.out.println("isWritable-> "+isWritable);

    Path sourcePath      = Paths.get(file.toString());
    String origName = file.getFileName().toString();
    String newName = origName.replaceAll("POPCORN-", "");
    if (isWritable&&!isDirectory) {




        System.out.println("fname-> "+origName);
        /*get the path of the directory*/
        String baseLoc = file.getParent().toString();
        System.out.println("baseLoc-> "+baseLoc);
        if (origName.contains("POPCORN-")  /*|| origName.contains("#") || origName.contains("@")*/){

            System.out.println("Orig name-> "+origName);
            /*origName = origName.replaceAll("&", "_and_");
        origName = origName.replaceAll("@", "_at_");*/


            System.out.println("New Name-> "+newName);
            String newLoc = baseLoc+File.separator+newName;//having "/" hardcoded is not cross-platform.
            System.out.println("newLoc-> "+newLoc);
            //File newFile = new File(newLoc);


            Path destinationPath = Paths.get(newLoc);

            Files.move(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING);

        } else {
            System.out.println("No write permission");
        }
    }else{

        /*if(origName.contains("POPCORN-")  || origName.contains("#") || origName.contains("@")){
            Files.copy(sourcePath, sourcePath.resolveSibling(newName),StandardCopyOption.REPLACE_EXISTING);
        }*/
    }
}



public static void renameDirectory(Path file) throws IOException {


    boolean isDirectory = Files.isDirectory(file);
    boolean isWritable = Files.isWritable(file);
    System.out.println("isDirectory-> "+isDirectory);
    System.out.println("isWritable-> "+isWritable);

    Path sourcePath      = Paths.get(file.toString());
    String origName = file.getFileName().toString();
    String newName = origName.replaceAll("POPCORN-", "");
    if (isWritable&&isDirectory) {

            if(origName.contains("POPCORN-")  /*|| origName.contains("#") || origName.contains("@")*/){
                Files.move(sourcePath, sourcePath.resolveSibling(newName),StandardCopyOption.ATOMIC_MOVE);
            }

        } else {
            System.out.println("No write permission");
        }
    }
}

在上面的代码中,我可以成功地重命名文件。但是下面的异常被抛出

Exception in thread "main" java.nio.file.AccessDeniedException: D:\root\POPCORN-folder1 -> D:\root\folder1
at sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsFileCopy.move(Unknown Source)
at sun.nio.fs.WindowsFileSystemProvider.move(Unknown Source)
at java.nio.file.Files.move(Unknown Source)
at com.din.pach.FileNio.renameDirectory(FileNio.java:121)
at com.din.pach.FileNio$1.postVisitDirectory(FileNio.java:45)
at com.din.pach.FileNio$1.postVisitDirectory(FileNio.java:1)
at java.nio.file.Files.walkFileTree(Unknown Source)
at java.nio.file.Files.walkFileTree(Unknown Source)
at com.din.pach.FileNio.main(FileNio.java:19)

实现基于本文Java NIO Files

这是Renaming a folder name which has sub directories is not working using java File.rename.to()的续集

编辑:我已启用所有文件夹和文件的写入权限。

但是没有答案。

更新:更新了完整的控制台输出

   isDirectory-> false
   isWritable-> true
   fname-> popcorn-file1.txt
   baseLoc-> D:\root\popcorn-folder1
   Orig name-> popcorn-file1.txt
   New Name-> file1.txt
   newLoc-> D:\root\popcorn-folder1\file1.txt
   ====================================================================
   isDirectory-> false
   isWritable-> true
   fname-> popcorn-subfile1.txt
   baseLoc-> D:\root\popcorn-folder1\popcorn-subfolder1
   Orig name-> popcorn-subfile1.txt
   New Name-> subfile1.txt
   newLoc-> D:\root\popcorn-folder1\popcorn-subfolder1\subfile1.txt
   ====================================================================
   isDirectory-> true
   isWritable-> true
   isDirectory-> true
   isWritable-> true
   Exception in thread "main" java.nio.file.AccessDeniedException: D:\root\popcorn-folder1 -> D:\root\folder1
at sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsFileCopy.move(Unknown Source)
at sun.nio.fs.WindowsFileSystemProvider.move(Unknown Source)
at java.nio.file.Files.move(Unknown Source)
at com.din.pach.FileNio.renameDirectory(FileNio.java:121)
at com.din.pach.FileNio$1.postVisitDirectory(FileNio.java:45)
at com.din.pach.FileNio$1.postVisitDirectory(FileNio.java:1)
at java.nio.file.Files.walkFileTree(Unknown Source)
at java.nio.file.Files.walkFileTree(Unknown Source)
at com.din.pach.FileNio.main(FileNio.java:19)

【问题讨论】:

  • 文件夹中的文件是否打开?
  • @Xtreme:没有文件/文件夹被打开。

标签: java file directory rename nio


【解决方案1】:

如 Java nio 库的 java 文档中所述 -

java.nio.file.AccessDeniedException 是当文件系统操作被拒绝时抛出的 Checked 异常,通常是由于文件权限或其他访问检查。

您解决此问题的第一步是检查您是否对尝试更改其名称的整个目录具有写入权限。

【讨论】:

  • 在上述结果中,子文件夹 1、子文件 1、文件 1 被重命名,然后在重命名 POPCORN-子文件夹 2 -> 子文件夹 2 时抛出异常。我删除了根文件夹属性中的“只读”选项后具有写入权限
  • 你能试试我的代码吗?我猜这与 preVisitDirectory() 函数和 postVisitDirectory() 回调函数有关
  • 能不能添加控制台输出直到出现异常?
【解决方案2】:

不幸的是,这个问题的真正根源很难检测,因为您的问题仅包含大量修改和修剪的样本数据。
实际上,您尝试为两个或多个文件夹分配相同的名称。 (例如“folder1”和“folder2”都应该重命名为“directory”)。

由于设置了 CopyOption StandardCopyOption.ATOMIC_MOVE,您只会得到误导性的 java.nio.file.AccessDeniedException 而不是 FileAlreadyExistsException¹ 或 DirectoryNotEmptyException²。

现在为避免这种情况,您需要检查文件夹是否已存在:

public static void renameDirectory(Path file) throws IOException {
    boolean isDirectory = Files.isDirectory(file);
    if(isDirectory) {
        Path sourcePath = Paths.get(file.toString());
        String origName = file.getFileName().toString();

        if(origName.contains("POPCORN-")) {
            String newName = origName.replaceAll("POPCORN-", "");
            Path destinationPath = sourcePath.resolveSibling(newName);

            // Check if the folder doesn't exists
            if(!Files.exists()) {
                // You can rename the folder without any difficulty
                Files.move(sourcePath, destinationPath, StandardCopyOption.ATOMIC_MOVE);
            } else {
                // Print warning
                System.err.println("Directory already exists! Try to rename \""+sourcePath+"\" to \""+destinationPath+"\"");
                // Here you could add some code to propably handel this case. e.g. merge the folders or create another name
            }
        }
    }
}

¹:当您使用 Files.move(sourcePath, destinationPath) 并且目标已存在时,将抛出 FileAlreadyExistsException

²:当您使用Files.move(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING) 并且目标文件夹包含文件或文件夹时,会抛出DirectoryNotEmptyException

【讨论】:

    猜你喜欢
    • 2014-08-11
    • 1970-01-01
    • 2016-02-05
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 1970-01-01
    • 2014-02-07
    • 1970-01-01
    相关资源
    最近更新 更多