How to rename the folders and subfolders including

2019-08-26 20:30发布

问题:

I cant able to rename the folder which contains a files or sub folders in it.

My Folder structure is

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

My resulting Directory should be

D:
  root
      folder1     
           subfolder1   
               subfile1
           file1         
      folder2 
           subfolder2  
           file2  

My tried code is

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

In above code, I can rename the files successfully. But below exception is thrown

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)

the implementation is based on this article Java NIO Files

This is sequel of Renaming a folder name which has sub directories is not working using java File.rename.to()

EDIT: I have enabled the write permission for all the folders and files.

But there is no answer to it.

UPDATE: updated the Full console output

   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)

回答1:

As mentioned in the java docs of Java nio library -

java.nio.file.AccessDeniedException is a Checked exception thrown when a file system operation is denied, typically due to a file permission or other access check.

Your first step to solve this problem is to check if you have write permissions to the whole directory you are trying to change his name.



回答2:

Unfortunately the real source of this problem is hard to detect, since your question only contains heavy modified and trimmed sample data.
Actually you tried to assign the same name too two or more folders. (e.g. "folder1" and "folder2" both should be renamed to "directory").

Since the CopyOption StandardCopyOption.ATOMIC_MOVE is set you only get the misleading java.nio.file.AccessDeniedException instead of FileAlreadyExistsException¹ or DirectoryNotEmptyException².

Now to avoid this you need to check if the folder already exists:

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 would be thrown when you use Files.move(sourcePath, destinationPath) and the destination already exists.

²: DirectoryNotEmptyException would be thrown when you use Files.move(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING) and the folder at the destination contains a file or folder.