문제

Java에서 전체 디렉토리를 재귀 적으로 삭제하는 방법이 있습니까?

일반적인 경우 빈 디렉토리를 삭제할 수 있습니다. 그러나 내용으로 전체 디렉토리를 삭제할 때는 더 이상 간단하지 않습니다.

Java의 내용으로 전체 디렉토리를 어떻게 삭제합니까?

도움이 되었습니까?

해결책

체크 아웃해야합니다 아파치의 공통-오. 그것은 있습니다 파일 당신이 원하는 것을 할 수있는 수업.

FileUtils.deleteDirectory(new File("directory"));

다른 팁

Java 7을 사용하면 마침내 할 수 있습니다 신뢰할 수있는 Symlink Detection으로이를 수행하십시오. (나는 Apache의 Commons-Io를 가지고 있다고 생각하지 않습니다 믿을 수 있는 이 시점에서 Symlink Detection은 mklink.)

역사를 위해 여기에 자바 이전의 답변이 있습니다. Symlinks를 따릅니다.

void delete(File f) throws IOException {
  if (f.isDirectory()) {
    for (File c : f.listFiles())
      delete(c);
  }
  if (!f.delete())
    throw new FileNotFoundException("Failed to delete file: " + f);
}

Java 7+에서는 사용할 수 있습니다 Files 수업. 코드는 매우 간단합니다.

Path directory = Paths.get("/tmp");
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
   @Override
   public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
       Files.delete(file);
       return FileVisitResult.CONTINUE;
   }

   @Override
   public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
       Files.delete(dir);
       return FileVisitResult.CONTINUE;
   }
});

Java 7 Symlink 처리 기능을 갖춘 보행 디렉토리에 대한 지원 :

import java.nio.file.*;

public static void removeRecursive(Path path) throws IOException
{
    Files.walkFileTree(path, new SimpleFileVisitor<Path>()
    {
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                throws IOException
        {
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException
        {
            // try to delete the file anyway, even if its attributes
            // could not be read, since delete-only access is
            // theoretically possible
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException
        {
            if (exc == null)
            {
                Files.delete(dir);
                return FileVisitResult.CONTINUE;
            }
            else
            {
                // directory iteration failed; propagate exception
                throw exc;
            }
        }
    });
}

나는 이것을 플랫폼 별 방법의 폴백으로 사용합니다 (이것에서 테스트되지 않았습니다 암호):

public static void removeDirectory(Path directory) throws IOException
{
    // does nothing if non-existent
    if (Files.exists(directory))
    {
        try
        {
            // prefer OS-dependent directory removal tool
            if (SystemUtils.IS_OS_WINDOWS)
                Processes.execute("%ComSpec%", "/C", "RD /S /Q \"" + directory + '"');
            else if (SystemUtils.IS_OS_UNIX)
                Processes.execute("/bin/rm", "-rf", directory.toString());
        }
        catch (ProcessExecutionException | InterruptedException e)
        {
            // fallback to internal implementation on error
        }

        if (Files.exists(directory))
            removeRecursive(directory);
    }
}

(SystemUtils는 왔습니다 Apache Commons Lang. 프로세스는 비공개이지만 그 행동은 분명해야합니다.)

원 라이너 솔루션 (Java8) 시작 디렉토리를 포함하여 모든 파일과 디렉토리를 재귀 적으로 삭제하려면 다음과 같습니다.

Files.walk(Paths.get("c:/dir_to_delete/"))
                .map(Path::toFile)
                .sorted((o1, o2) -> -o1.compareTo(o2))
                .forEach(File::delete);

반전 순서에 비교기를 사용합니다. 그렇지 않으면 file :: delete는 비어 있지 않은 디렉토리를 삭제할 수 없습니다. 따라서 디렉토리를 유지하고 파일 만 삭제하려면 Sorted ()에서 비교기를 제거하십시오. 또는 정렬을 완전히 제거하고 파일 필터를 추가하십시오.

Files.walk(Paths.get("c:/dir_to_delete/"))
                .filter(Files::isRegularFile)
                .map(Path::toFile)
                .forEach(File::delete);

내 솔루션이 Erickson 's와 거의 동일하다는 것을 보았습니다. 정적 방법으로 패키지되었습니다. 이것을 어딘가에 떨어 뜨리십시오. 아파치 커먼즈를 설치하는 것보다 훨씬 가벼운 무게가 훨씬 간단합니다.

public class FileUtils {
    /**
     * By default File#delete fails for non-empty directories, it works like "rm". 
     * We need something a little more brutual - this does the equivalent of "rm -r"
     * @param path Root File Path
     * @return true iff the file and all sub files/directories have been removed
     * @throws FileNotFoundException
     */
    public static boolean deleteRecursive(File path) throws FileNotFoundException{
        if (!path.exists()) throw new FileNotFoundException(path.getAbsolutePath());
        boolean ret = true;
        if (path.isDirectory()){
            for (File f : path.listFiles()){
                ret = ret && deleteRecursive(f);
            }
        }
        return ret && path.delete();
    }
}

스택이있는 솔루션 및 재귀 방법이없는 솔루션 :

File dir = new File("/path/to/dir");
File[] currList;
Stack<File> stack = new Stack<File>();
stack.push(dir);
while (! stack.isEmpty()) {
    if (stack.lastElement().isDirectory()) {
        currList = stack.lastElement().listFiles();
        if (currList.length > 0) {
            for (File curr: currList) {
                stack.push(curr);
            }
        } else {
            stack.pop().delete();
        }
    } else {
        stack.pop().delete();
    }
}

구아바 가졌다 Files.deleteRecursively(File) 지원됩니다 구아바 9.

에서 구아바 10:

감가 상각 된. 이 방법은 상징적 인 감지 및 레이스 조건이 좋지 않습니다. 이 기능은 다음과 같은 운영 체제 명령으로 배포하여 적절하게 지원할 수 있습니다. rm -rf 또는 del /s. 이 방법은 Guava Release 11.0의 Guava에서 제거 될 예정입니다.

따라서 그러한 방법은 없습니다 구아바 11.

봄이 있다면 사용할 수 있습니다 FileSystemutils.deleterEcursively:

import org.springframework.util.FileSystemUtils;

boolean success = FileSystemUtils.deleteRecursively(new File("directory"));
for(Path p : Files.walk(directoryToDelete).
        sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
        toArray(Path[]::new))
{
    Files.delete(p);
}

또는 당신이 처리하고 싶다면 IOException:

Files.walk(directoryToDelete).
    sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
    forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });
public void deleteRecursive(File path){
    File[] c = path.listFiles();
    System.out.println("Cleaning out folder:" + path.toString());
    for (File file : c){
        if (file.isDirectory()){
            System.out.println("Deleting file:" + file.toString());
            deleteRecursive(file);
            file.delete();
        } else {
            file.delete();
        }
    }
    path.delete();
}
static public void deleteDirectory(File path) 
{
    if (path == null)
        return;
    if (path.exists())
    {
        for(File f : path.listFiles())
        {
            if(f.isDirectory()) 
            {
                deleteDirectory(f);
                f.delete();
            }
            else
            {
                f.delete();
            }
        }
        path.delete();
    }
}

Symlinks와 위의 코드로 실패하는 두 가지 방법 ... 솔루션을 모릅니다.

방법 #1

테스트를 만들려면 이것을 실행하십시오.

echo test > testfile
mkdir dirtodelete
ln -s badlink dirtodelete/badlinktodelete

여기에는 테스트 파일 및 테스트 디렉토리가 표시됩니다.

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

그런 다음 Commons-IO DeletEdirectory ()를 실행하십시오. 파일을 찾을 수 없다고 말하면 충돌합니다. 다른 예가 여기서 무엇을하는지 잘 모르겠습니다. Linux RM 명령은 단순히 링크를 삭제하고 디렉토리의 rm -r도 삭제합니다.

Exception in thread "main" java.io.FileNotFoundException: File does not exist: /tmp/dirtodelete/linktodelete

방법 #2

테스트를 만들려면 이것을 실행하십시오.

mkdir testdir
echo test > testdir/testfile
mkdir dirtodelete
ln -s ../testdir dirtodelete/dirlinktodelete

여기에는 테스트 파일 및 테스트 디렉토리가 표시됩니다.

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

그런 다음 Commons-IO DeletEdirectory () 또는 People이 게시 한 예제 코드를 실행하십시오. 디렉토리뿐만 아니라 삭제되는 디렉토리 외부에있는 TestFile을 삭제합니다. (디렉토리를 암시 적으로 해석하고 내용을 삭제합니다). rm -r는 링크 만 삭제합니다. 이와 같은 항목을 사용해야합니다. "찾기 -l dirtodelete -type f -exec rm {} ;".

$ ls dirtodelete testdir
ls: cannot access dirtodelete: No such file or directory
testdir:

당신은 사용할 수 있습니다 :

org.apache.commons.io.FileUtils.deleteQuietly(destFile);

파일을 삭제하고 예외를 던지지 않습니다. 파일이 디렉토리 인 경우 모든 하위 디렉터를 삭제하십시오. file.delete () 와이 메소드의 차이점은 다음과 같습니다. 삭제할 디렉토리는 비어있을 필요가 없습니다. 파일이나 디렉토리를 삭제할 수없는 경우 예외가 발생하지 않습니다.

방법에서 예외가 발생한 접근 방식과 일관되게 예외를 처리하는 최적의 솔루션은 해당 메소드가 무엇을 시도하고 실패했는지 항상 설명해야합니다.

private void deleteRecursive(File f) throws Exception {
    try {
        if (f.isDirectory()) {
            for (File c : f.listFiles()) {
                deleteRecursive(c);
            }
        }
        if (!f.delete()) {
            throw new Exception("Delete command returned false for file: " + f);
        }
    } 
    catch (Exception e) {
        throw new Exception("Failed to delete the folder: " + f, e);
    }
}

레거시 프로젝트에서는 기본 Java 코드를 만들어야합니다. Paulitex 코드와 유사한이 코드를 만듭니다. 저거 봐:

public class FileHelper {

   public static boolean delete(File fileOrFolder) {
      boolean result = true;
      if(fileOrFolder.isDirectory()) {
         for (File file : fileOrFolder.listFiles()) {
            result = result && delete(file);
         }
      }
      result = result && fileOrFolder.delete();
      return result;
   } 
}

그리고 단위 테스트 :

public class FileHelperTest {

    @Before
    public void setup() throws IOException {
       new File("FOLDER_TO_DELETE/SUBFOLDER").mkdirs();
       new File("FOLDER_TO_DELETE/SUBFOLDER_TWO").mkdirs();
       new File("FOLDER_TO_DELETE/SUBFOLDER_TWO/TEST_FILE.txt").createNewFile();
    }

    @Test
    public void deleteFolderWithFiles() {
       File folderToDelete = new File("FOLDER_TO_DELETE");
       Assert.assertTrue(FileHelper.delete(folderToDelete));
       Assert.assertFalse(new File("FOLDER_TO_DELETE").exists());
    }

}

다음은 명령 줄 인수를 받아들이는 Bare Bones의 주요 방법입니다. 자신의 오류 확인을 추가하거나 적합한 방법에 맞게 만들어야 할 수도 있습니다.

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

public class DeleteFiles {

/**
 * @param intitial arguments take in a source to read from and a 
 * destination to read to
 */
    public static void main(String[] args)
                     throws FileNotFoundException,IOException {
        File src = new File(args[0]);
        if (!src.exists() ) {
            System.out.println("FAILURE!");
        }else{
            // Gathers files in directory
            File[] a = src.listFiles();
            for (int i = 0; i < a.length; i++) {
                //Sends files to recursive deletion method
                fileDelete(a[i]);
            }
            // Deletes original source folder
            src.delete();
            System.out.println("Success!");
        }
    }

    /**
     * @param srcFile Source file to examine
     * @throws FileNotFoundException if File not found
     * @throws IOException if File not found
     */
    private static void fileDelete(File srcFile)
                     throws FileNotFoundException, IOException {
        // Checks if file is a directory
        if (srcFile.isDirectory()) {
            //Gathers files in directory
            File[] b = srcFile.listFiles();
            for (int i = 0; i < b.length; i++) {
                //Recursively deletes all files and sub-directories
                fileDelete(b[i]);
            }
            // Deletes original sub-directory file
            srcFile.delete();
        } else {
            srcFile.delete();
        }
    }
}

도움이되기를 바랍니다!

아래 코드는 주어진 폴더의 모든 내용을 재귀 적으로 삭제합니다.

boolean deleteDirectory(File directoryToBeDeleted) {
    File[] allContents = directoryToBeDeleted.listFiles();
    if (allContents != null) {
        for (File file : allContents) {
            deleteDirectory(file);
        }
    }
    return directoryToBeDeleted.delete();
}

아마도이 문제에 대한 해결책은 Erickson의 답변에서 코드를 사용하여 파일 클래스의 삭제 방법을 다시 구현하는 것일 수 있습니다.

public class MyFile extends File {

  ... <- copy constructor

  public boolean delete() {
    if (f.isDirectory()) {
      for (File c : f.listFiles()) {
        return new MyFile(c).delete();
      }
    } else {
        return f.delete();
    }
  }
}

Commons없이 io 및 <Java SE 7

public static void deleteRecursive(File path){
            path.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    if (pathname.isDirectory()) {
                        pathname.listFiles(this);
                        pathname.delete();
                    } else {
                        pathname.delete();
                    }
                    return false;
                }
            });
            path.delete();
        }

File.delete ()를 사용하여 파일을 쉽게 삭제할 수 있지만 디렉토리는 삭제해야합니다. 재귀를 사용하여 쉽게 수행하십시오. 예를 들어:

public static void clearFolders(String[] args) {
        for(String st : args){
            File folder = new File(st);
            if (folder.isDirectory()) {
                File[] files = folder.listFiles();
                if(files!=null) { 
                    for(File f: files) {
                        if (f.isDirectory()){
                            clearFolders(new String[]{f.getAbsolutePath()});
                            f.delete();
                        } else {
                            f.delete();
                        }
                    }
                }
            }
        }
    }

더 안전한 사용을위한 3 가지 안전 기준이있는이 루틴을 코딩했습니다.

package ch.ethz.idsc.queuey.util;

import java.io.File;
import java.io.IOException;

/** recursive file/directory deletion
 * 
 * safety from erroneous use is enhanced by three criteria
 * 1) checking the depth of the directory tree T to be deleted
 * against a permitted upper bound "max_depth"
 * 2) checking the number of files to be deleted #F
 * against a permitted upper bound "max_count"
 * 3) if deletion of a file or directory fails, the process aborts */
public final class FileDelete {
    /** Example: The command
     * FileDelete.of(new File("/user/name/myapp/recordings/log20171024"), 2, 1000);
     * deletes given directory with sub directories of depth of at most 2,
     * and max number of total files less than 1000. No files are deleted
     * if directory tree exceeds 2, or total of files exceed 1000.
     * 
     * abort criteria are described at top of class
     * 
     * @param file
     * @param max_depth
     * @param max_count
     * @return
     * @throws Exception if criteria are not met */
    public static FileDelete of(File file, int max_depth, int max_count) throws IOException {
        return new FileDelete(file, max_depth, max_count);
    }

    // ---
    private final File root;
    private final int max_depth;
    private int removed = 0;

    /** @param root file or a directory. If root is a file, the file will be deleted.
     *            If root is a directory, the directory tree will be deleted.
     * @param max_depth of directory visitor
     * @param max_count of files to delete
     * @throws IOException */
    private FileDelete(final File root, final int max_depth, final int max_count) throws IOException {
        this.root = root;
        this.max_depth = max_depth;
        // ---
        final int count = visitRecursively(root, 0, false);
        if (count <= max_count) // abort criteria 2)
            visitRecursively(root, 0, true);
        else
            throw new IOException("more files to be deleted than allowed (" + max_count + "<=" + count + ") in " + root);
    }

    private int visitRecursively(final File file, final int depth, final boolean delete) throws IOException {
        if (max_depth < depth) // enforce depth limit, abort criteria 1)
            throw new IOException("directory tree exceeds permitted depth");
        // ---
        int count = 0;
        if (file.isDirectory()) // if file is a directory, recur
            for (File entry : file.listFiles())
                count += visitRecursively(entry, depth + 1, delete);
        ++count; // count file as visited
        if (delete) {
            final boolean deleted = file.delete();
            if (!deleted) // abort criteria 3)
                throw new IOException("cannot delete " + file.getAbsolutePath());
            ++removed;
        }
        return count;
    }

    public int deletedCount() {
        return removed;
    }

    public void printNotification() {
        int count = deletedCount();
        if (0 < count)
            System.out.println("deleted " + count + " file(s) in " + root);
    }
}

글쎄, 예를 들어 봅시다.

import java.io.File;
import java.io.IOException;

public class DeleteDirectory
{
   private static final String folder = "D:/project/java";

   public static void main(String[] args) throws IOException
   {
      File fl = new File(folder);
      if(!fl.exists()) // checking if directory exists
      {
         System.out.println("Sorry!! directory doesn't exist.");
      }
      else
      {
         DeleteDirectory dd = new DeleteDirectory();
         dd.deleteDirectory(fl);
      }
   }

   public void deleteDirectory(File file) throws IOException
   {
      if(file.isDirectory())
      {
         if(file.list().length == 0)
         { 
            deleteEmptyDirectory(file); // here if directory is empty delete we are deleting
         }
         else
         {
            File fe[] = file.listFiles();
            for(File deleteFile : fe)
            {
               deleteDirectory(deleteFile); // recursive call
            }
            if(file.list().length == 0)
            {
               deleteEmptyDirectory(file);
            }
         }
      }
      else
      {
         file.delete();
         System.out.println("File deleted : " + file.getAbsolutePath());
      }
   }

   private void deleteEmptyDirectory(File fi)
   {
      fi.delete();
      System.out.println("Directory deleted : " + fi.getAbsolutePath());
   }
}

자세한 내용은 아래 리소스를 참조하십시오

디렉토리 삭제

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top