如何使用Java NIO文件递归重命名文件夹和子文件夹,包括其中存在的文件?

时间:2018-01-18 11:30:17

标签: java file directory rename nio

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

我的文件夹结构是

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)

2 个答案:

答案 0 :(得分:0)

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

  

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

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

答案 1 :(得分:0)

不幸的是,这个问题的真正根源很难被发现,因为您的问题只包含大量修改和修整的样本数据 实际上你试图为两个或更多文件夹分配相同的名称。 (例如“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
            }
        }
    }
}
当您使用FileAlreadyExistsException并且目的地已经存在时,

¹:Files.move(sourcePath, destinationPath)会被抛出。

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