Xóa các thư mục đệ quy trong Java


382

Có cách nào để xóa toàn bộ thư mục đệ quy trong Java không?

Trong trường hợp bình thường có thể xóa một thư mục trống. Tuy nhiên, khi nói đến việc xóa toàn bộ thư mục với nội dung, nó không còn đơn giản nữa.

Làm thế nào để bạn xóa toàn bộ thư mục với nội dung trong Java?


4
File.delete () chỉ cần trả về false khi gọi nó với một thư mục không trống.
Ben S

Nếu bạn đang sử dụng Java 8, hãy xem câu trả lời của @ RoK.
Robin

Câu trả lời:


462

Bạn nên kiểm tra commons-io của Apache . Nó có một lớp FileUtils sẽ làm những gì bạn muốn.

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

3
Hàm này có thể bao bọc mã mà erickson cung cấp trong câu trả lời của anh ta.
paweloque

14
Nó kỹ lưỡng hơn một chút. Nó xử lý những thứ như các liên kết tượng trưng chính xác trên Linux / Unix. svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/ Kẻ
Steve K



Tại sao thêm một phụ thuộc khác khi Java có một cơ sở ngoài hộp? Xem câu trả lời của RoK trên trang này hoặc stackoverflow.com/questions353888192/iêu
foo

190

Với Java 7, cuối cùng chúng ta cũng có thể làm điều này với phát hiện symlink đáng tin cậy. (Tôi không coi commons-io của Apache có khả năng phát hiện liên kết tượng trưng đáng tin cậy tại thời điểm này, vì nó không xử lý các liên kết trên Windows được tạo bằng mklink.)

Vì lợi ích của lịch sử, đây là câu trả lời trước Java 7, theo sau các liên kết tượng trưng.

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

11
File.delete () không có chức năng đó.
Ben S

14
@Erickson: Không phải FileNotFoundException là một ngoại lệ kém cho lỗi xóa? Nếu tập tin thực sự không còn ở đó nữa, thì nó đã bị xóa rồi, điều đó có nghĩa là về mặt ngữ nghĩa, việc xóa không thất bại - nó không có gì để làm. Và nếu nó thất bại vì một số lý do khác, thì đó không phải là vì tập tin không được tìm thấy.
Lawrence Dol

46
Hãy rất cẩn thận . Điều này sẽ dereference symlinks. Nếu bạn đang sử dụng linux, và có một thư mục foocó liên kết foo/linknhư vậy link->/, việc gọi delete(new File(foo)) sẽ xóa càng nhiều hệ thống tập tin của bạn khi người dùng của bạn được phép !!
Miquel

4
@Miquel Điều đó không có ý nghĩa - Tại sao chúng ta muốn cẩn thận? Chắc chắn điểm của mã được cung cấp là loại bỏ toàn bộ thư mục, đó là những gì nó dường như làm. Tôi không hiểu những gì nguy hiểm ở đây.
Joehot200

12
@ Joehot200 bạn đúng, gọi xóa trên một thư mục symlink sẽ không xóa thư mục, chỉ là symlink. Xóa thư mục thực sự sẽ yêu cầu theo liên kết tượng trưng một cách rõ ràng bằng ReadSymbolicLink . Lỗi của tôi! Được phát hiện tốt
Miquel

148

Trong Java 7+, bạn có thể sử dụng Fileslớp. Mã rất đơn giản:

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

2
Giải pháp này có vẻ rất thanh lịch và không chứa logic truyền tải thư mục nào cả!
Zero3

1
"Để tìm một viên ngọc lặn sâu xuống đại dương.". Đây là giải pháp gọn gàng nhất mà tôi tìm thấy. Phải lặn sâu để tìm thấy nó. Xuất sắc!
Basil Musa

20
"Mã là" KHÔNG "rất đơn giản" chỉ đơn giản là xóa một thư mục :-) Nhưng hey đó là giải pháp tốt nhất trong java thuần túy tôi nghĩ.
Mat

1
Xin lưu ý rằng quá tải walkFileTree được sử dụng ở đây " không tuân theo các liên kết tượng trưng ". (Javadoc: docs.oracle.com/javase/7/docs/api/java/nio/file/ gợi )
Stephan

1
Bạn có lẽ nên gọi super.postVisitDirectory(dir, exc);theo postVisitDirectoryphương thức của mình , để nổ tung nếu đi bộ không thể liệt kê một thư mục.
Tom Anderson

68

Giải pháp một lớp (Java8) để xóa tất cả các tệp và thư mục theo cách đệ quy bao gồm cả thư mục bắt đầu:

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

Chúng tôi sử dụng một bộ so sánh cho thứ tự đảo ngược, nếu không File :: xóa sẽ không thể xóa thư mục có thể không trống. Vì vậy, nếu bạn muốn giữ các thư mục và chỉ xóa các tệp, chỉ cần xóa bộ so sánh trong sort () hoặc xóa hoàn toàn sắp xếp và thêm bộ lọc tệp:

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

1
Bạn cần thay đổi sắp xếp trong cái đầu tiên thành .sort (so sánh :: ReverseOrder) để xóa tất cả các thư mục. Mặt khác, thư mục mẹ được sắp xếp trước đứa trẻ, và do đó sẽ không xóa vì nó không trống. Câu trả lời tuyệt vời cho những người sử dụng Java 8!
Robin

1
Cách đúng là .sorted(Comparator.reverseOrder())những gợi ý Comparator::reverseOrderkhông không làm việc. Xem: stackoverflow.com/questions/43036611/ từ
user1156544

4
Robin, chú ý ở dấu trừ trong "-o1.compareTo (o2)". Nó giống như .sorted (Comparator.reverseOrder)
Hàn Quốc

Là Files.walk tuần tự? Hoặc câu trả lời này có cần forEachOrdered thay vì forEach để tránh cố gắng xóa các thư mục không trống?
Silwing

Chỉ cần sử dụng : .sorted((f1, f2) -> f2.compareTo(f1)), so sánh f2với f1thay vì f1với f2.
Beto Neto

67

Java 7 đã thêm hỗ trợ cho các thư mục đi bộ với việc xử lý 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;
            }
        }
    });
}

Tôi sử dụng điều này như một dự phòng từ các phương thức dành riêng cho nền tảng (trong mã chưa được kiểm tra này ):

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 là từ Apache Commons Lang . Các quy trình là riêng tư nhưng hành vi của nó phải rõ ràng.)


Tôi tìm thấy một vấn đề với Files.walkFileTree - không đủ để thực hiện phiên bản xóa đệ quy trong đó bạn tiếp tục xóa các tệp cho đến khi bạn hết tùy chọn. Nó phù hợp với phiên bản không nhanh, nhưng không nhanh luôn không phải là điều bạn muốn (ví dụ: nếu bạn đang dọn dẹp các tệp tạm thời, bạn muốn xóa ngay bây giờ, không phải là không nhanh.)
Trejkaz

Tôi không thấy lý do tại sao điều đó là đúng. Bạn có thể xử lý các lỗi theo cách bạn muốn - bạn không bắt buộc phải thất bại nhanh. Vấn đề duy nhất tôi có thể thấy trước là nó có thể không xử lý các tệp mới được tạo trong quá trình đi bộ của thư mục hiện tại, nhưng đó là một tình huống duy nhất phù hợp hơn với một giải pháp tùy chỉnh.
Trevor Robinson

1
Nếu bạn loại bỏ lỗi từ visitFile và gọi walkFileTree trên một tệp không thành công, bạn sẽ không gặp lỗi (vì vậy visitFile phải truyền bất kỳ lỗi nào xảy ra.) Nếu bạn đang xóa một thư mục và không xóa được một tệp, cuộc gọi lại duy nhất được gọi là postVisitDirectory. tức là, nó không truy cập các tệp khác trong thư mục nếu bạn gặp lỗi khi truy cập một tệp. Đó là thứ tôi nghĩ. Tôi chắc chắn có một số cách để giải quyết vấn đề này, nhưng đến thời điểm này, chúng tôi đã viết nhiều mã hơn một thói quen xóa đệ quy truyền thống, vì vậy chúng tôi quyết định không sử dụng nó.
Trejkaz

Cảm ơn mã đầu tiên của bạn, nó rất hữu ích với tôi, nhưng tôi đã phải thay đổi nó, bởi vì nó không hoàn thành một đồng bằng đơn giản: Tôi phải bỏ qua ngoại lệ trong "postVisitDirectory" và trả về TIẾP TỤC bất kể vì cây đơn giản sau không thể hoàn toàn bị xóa: Một thư mục bên trong có một thư mục khác trong đó là một tệp. Tất cả đều đơn giản / bình thường như trên Windows.
Chủ tịch Dreamspace

Tất cả bắt đầu từ một java.nio.file.DirectoryNotEmptyException tôi có. Tôi phát hiện ra trường hợp visitFileFails được sử dụng. Nếu cấu trúc thư mục của bạn có một liên kết loại đường nối trong windows. Điều này có thể gây ra cho bạn 2 vấn đề: *) Files.walkFileTree theo liên kết vào đường giao nhau và xóa mọi thứ ở đó. *) Nếu thư mục đích của hàm đã bị xóa thì việc phân tích liên kết bởi Files.walkFileTree không thành công với NoSuchFileException được bắt trong visitFileFails.
Andres Luuk

34

Chỉ cần thấy giải pháp của tôi ít nhiều giống với erickson, chỉ được đóng gói như một phương thức tĩnh. Bỏ cái này ở đâu đó, nó nhẹ hơn nhiều so với việc cài đặt tất cả Apache Commons cho một cái gì đó (như bạn có thể thấy) khá đơn giản.

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

20

Một giải pháp với một ngăn xếp và không có phương pháp đệ quy:

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

2
+1 để sử dụng ngăn xếp. Điều này sẽ làm việc với các thư mục chứa mức độ sâu của các thư mục con lồng nhau trong khi các cách tiếp cận dựa trên ngăn xếp khác sẽ thất bại.
Nathan Osman

4
Thấy rằng bạn thường không gặp vấn đề gì khi lồng một vài trăm cuộc gọi phương thức, tôi nghĩ rằng bạn có khả năng gặp phải các hạn chế về hệ thống tệp trước đó rất nhiều.
Bombe

2
Hãy cẩn thận với các list*phương pháp cho lớp java.io.File. Từ Javadocs: "Trả về null nếu tên đường dẫn trừu tượng này không biểu thị một thư mục hoặc nếu xảy ra lỗi I / O." Vì vậy: if (currList.length > 0) {trở thànhif (null != currList && currList.length > 0) {
kevinarpe

1
Tôi sử dụng ArrayDeque thay vì Stack nhanh hơn một chút. (không đồng bộ)
Wytze


15

Quả ổi đã Files.deleteRecursively(File)hỗ trợ cho đến quả ổi 9 .

Từ ổi 10 :

Không dùng nữa Phương pháp này bị phát hiện liên kết tượng và điều kiện chủng tộc kém. Chức năng này có thể được hỗ trợ phù hợp chỉ bằng cách tách ra một lệnh hệ điều hành như rm -rfhoặc del /s. Phương pháp này dự kiến ​​sẽ được gỡ bỏ khỏi Guava trong phiên bản Guava 11.0.

Do đó, không có phương pháp như vậy trong ổi 11 .


6
Quá tệ. Tách ra có vẻ hơi thô và không xách tay. Nếu phiên bản Apache commons hoạt động chính xác, thì có lẽ không thể thực hiện được.
Andrew McKinlay

6
@andrew Việc triển khai Apache Commons sẽ có những vấn đề tương tự như những vấn đề khiến Guava gỡ bỏ việc triển khai của họ, xem code.google.com/p/guava-lologists/issues/detail?id=365
orip

Phiên bản apache commons phát hiện các liên kết tượng trưng và đơn giản là không đi qua con của tệp.
Ajax

5
Guava 21.0 đã thêm cái này dưới dạng MoreFiles.deleteRecursively () .
Robert Fleming

12
for(Path p : Files.walk(directoryToDelete).
        sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
        toArray(Path[]::new))
{
    Files.delete(p);
}

Hoặc nếu bạn muốn xử lý IOException:

Files.walk(directoryToDelete).
    sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
    forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });

2
Điều này giúp tôi đưa ra phiên bản Scala:Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
James Ward

Là sắp xếp thực sự cần thiết? Các walkphương pháp đã đảm bảo một traversal sâu-đầu tiên.
VGR

Bộ so sánh có thể được tái chế từ Collections.reverseOrder()đó mã của bạn sẽ cho for (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))rằng nó đã được nhập tĩnh.
namero999

@ namero999 Ý bạn là Comparator.reverseOrdersao? Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
Jeff

@Jeff khá chắc chắn rằng bạn đúng, chủ yếu là theo trí nhớ :)
namero999

11
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();
}

5
Phiên bản nâng cao với giá trị trả về boolean và không trùng lặp: pastebin.com/PqJyzQUx
Erik Kaplun

9
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();
    }
}

Mã đẹp, nhưng có một lỗi, khi sửa, nó hoạt động. Dòng f.delete()bên dưới deleteDirectory(f)sẽ ném NoSuchFileException vì deleteDirectory(f)đã xóa tệp đó. Mỗi thư mục sẽ trở thành một đường dẫn khi được truyền vào deleteDirectory(f)và bị xóa bởi path.delete(). Vì vậy, chúng tôi không cần f.delete()trong if f.isDerectoryphần. Vì vậy, chỉ cần xóa f.delete();dưới xóaDirectory (f) và nó sẽ hoạt động.
Triệu Nguyễn

5

Hai cách để thất bại với symlink và đoạn mã trên ... và không biết giải pháp.

Cách 1

Chạy này để tạo một bài kiểm tra:

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

Tại đây bạn thấy tập tin kiểm tra và thư mục kiểm tra của bạn:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

Sau đó chạy commons-io của bạn xóaDirectory (). Nó gặp sự cố nói rằng tập tin không được tìm thấy. Không chắc chắn những gì các ví dụ khác làm ở đây. Lệnh rm Linux chỉ đơn giản là xóa liên kết và rm -r trên thư mục cũng vậy.

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

Cách # 2

Chạy này để tạo một bài kiểm tra:

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

Tại đây bạn thấy tập tin kiểm tra và thư mục kiểm tra của bạn:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

Sau đó chạy commons-io xóaDirectory () hoặc mã ví dụ mà mọi người đã đăng. Nó xóa không chỉ thư mục, mà testfile của bạn nằm ngoài thư mục đang bị xóa. (Nó hủy bỏ thư mục ngầm và xóa nội dung). rm -r sẽ chỉ xóa liên kết. Bạn cần sử dụng một cái gì đó như thế này để xóa các tệp bị hủy đăng ký: "find -L Dirtodelete -type f -exec rm {} \;".

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

4

Bạn đã có thể sử dụng:

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

Xóa một tập tin, không bao giờ ném một ngoại lệ. Nếu tập tin là một thư mục, xóa nó và tất cả các thư mục con. Sự khác biệt giữa File.delete () và phương thức này là: Một thư mục cần xóa không phải trống. Không có ngoại lệ được ném khi một tập tin hoặc thư mục có thể bị xóa.


4

Một giải pháp tối ưu xử lý ngoại lệ một cách nhất quán với cách tiếp cận mà một ngoại lệ được ném ra từ một phương thức sẽ luôn mô tả phương thức đó đang cố gắng (và thất bại) để làm gì:

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

3

Trong các dự án cũ, tôi cần tạo mã Java riêng. Tôi tạo mã này tương tự như mã Paulitex. Xem đó:

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

Và bài kiểm tra đơn vị:

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

}

3

Mã bên dưới xóa đệ quy tất cả nội dung trong một thư mục nhất định.

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

2

Đây là một phương pháp chính xương trần chấp nhận một đối số dòng lệnh, bạn có thể cần phải nối thêm kiểm tra lỗi của riêng bạn hoặc tạo khuôn cho nó theo cách bạn thấy phù hợp.

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

Tôi hy vọng điều đó sẽ giúp!


1

Có lẽ một giải pháp cho vấn đề này có thể là thực hiện lại phương thức xóa của lớp Tệp bằng cách sử dụng mã từ câu trả lời của 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();
    }
  }
}

1
Tôi nghĩ rằng nó được triển khai vì nó bắt chước hành vi của hầu hết các tiện ích shell lệnh như "rm", "rmdir" và "del". Trong hai phương án, việc triển khai hiện tại chắc chắn giảm thiểu tiềm năng bất ngờ (và tức giận) chung. Nó sẽ không thay đổi.
erickson

4
Nói chung, các gói Java JRE duy nhất tôi thấy được mở rộng là từ Swing. Thông thường, mở rộng các lớp khác như java.io.File là một ý tưởng tồi, vì nó có khả năng khiến mọi thứ hành động theo những cách không ngờ tới.
Eddie

1

Không có Commons IO và <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();
        }

0

Mặc dù các tệp có thể dễ dàng bị xóa bằng file.delete (), các thư mục được yêu cầu để trống để được xóa. Sử dụng đệ quy để làm điều này một cách dễ dàng. Ví dụ:

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

0

tôi đã mã hóa thói quen này có 3 tiêu chí an toàn để sử dụng an toàn hơn.

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

0

Chà, giả sử một ví dụ,

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

Để biết thêm thông tin tham khảo tài nguyên dưới đây

Xóa thư mục


0

rm -rfđược nhiều performant hơnFileUtils.deleteDirectory .

Sau khi đo điểm chuẩn, chúng tôi thấy rằng việc sử dụng rm -rfnhanh hơn nhiều lần so với sử dụngFileUtils.deleteDirectory .

Tất nhiên, nếu bạn có một thư mục nhỏ hoặc đơn giản, điều đó sẽ không thành vấn đề nhưng trong trường hợp của chúng tôi, chúng tôi có nhiều gigabyte và các thư mục con được lồng sâu trong đó sẽ mất hơn 10 phút FileUtils.deleteDirectoryvà chỉ 1 phút với rm -rf.

Đây là triển khai Java thô của chúng tôi để làm điều đó:

// Delete directory given and all subdirectories and files (i.e. recursively).
//
static public boolean deleteDirectory( File file ) throws IOException, InterruptedException {

    if ( file.exists() ) {

        String deleteCommand = "rm -rf " + file.getAbsolutePath();
        Runtime runtime = Runtime.getRuntime();

        Process process = runtime.exec( deleteCommand );
        process.waitFor();

        return true;
    }

    return false;

}

Đáng để thử nếu bạn đang xử lý các thư mục lớn hoặc phức tạp.


Điều này hoạt động đa nền tảng ??
OneCricketeer

@ cricket_007 Những nền tảng nào?
Joshua Pinter

Các cửa sổ? OpenWrt? BSD?
OneCricketeer

1
@ cricket_007 Chắc chắn không phải Windows. Điều này đã được thử nghiệm và sử dụng trên Android và macOS.
Joshua Pinter

0

Quả ổi cung cấp một lớp lót : MoreFiles.deleteRecursively().

Không giống như nhiều ví dụ được chia sẻ, nó chiếm các liên kết tượng trưng và sẽ không (theo mặc định) xóa các tệp bên ngoài đường dẫn được cung cấp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.