Bạn có thể xóa các tập tin, thư mục hoặc liên kết. Với các liên kết tượng trưng, liên kết bị xóa và không phải là mục tiêu của liên kết. Với các thư mục, thư mục phải trống, nếu không việc xóa không thành công
Lớp Files
cung cấp hai phương thức xóa
Phương thức delete[Path]
xóa tệp hoặc đưa ra một ngoại lệ nếu việc xóa không thành công. Ví dụ: nếu tệp không tồn tại thì một NoSuchFileException
sẽ bị ném. Bạn có thể bắt ngoại lệ để xác định lý do xóa không thành công như sau
try { Files.delete[path]; } catch [NoSuchFileException x] { System.err.format["%s: no such" + " file or directory%n", path]; } catch [DirectoryNotEmptyException x] { System.err.format["%s not empty%n", path]; } catch [IOException x] { // File permission problems are caught here. System.err.println[x]; }
Phương thức
void deleteDirectoryRecursionJava6[File file] throws IOException { if [file.isDirectory[]] { File[] entries = file.listFiles[]; if [entries != null] { for [File entry : entries] { deleteDirectoryRecursionJava6[entry]; } } } if [!file.delete[]] { throw new IOException["Failed to delete " + file]; } }0 cũng xóa tệp nhưng nếu tệp không tồn tại thì không có ngoại lệ nào được ném ra. Thất bại âm thầm rất hữu ích khi bạn có nhiều luồng xóa tệp và bạn không muốn đưa ra một ngoại lệ chỉ vì một luồng đã làm như vậy trước
Xóa thư mục trống trong Java cũng đơn giản như gọi File. xóa [] [tiêu chuẩn IO] hoặc Tệp. phương thức xóa [] [NIO]. Tuy nhiên, nếu thư mục không trống [ví dụ: chứa một hoặc nhiều tệp hoặc thư mục con], các phương thức này sẽ từ chối xóa thư mục đó. Trong bài này tôi muốn trình bày một số cách để loại bỏ đệ quy thư mục cùng với nội dung của nó
Đệ quy chuẩn [Java 6 trở về trước]
Phương pháp đầu tiên loại bỏ đệ quy các tệp và thư mục khỏi cây thư mục bắt đầu từ các lá. Bởi vì nó sử dụng tệp lớp I/O cũ để thao tác trên các tệp và thư mục, nên phương pháp này có thể được sử dụng trong bất kỳ phiên bản Java nào
void deleteDirectoryRecursionJava6[File file] throws IOException { if [file.isDirectory[]] { File[] entries = file.listFiles[]; if [entries != null] { for [File entry : entries] { deleteDirectoryRecursionJava6[entry]; } } } if [!file.delete[]] { throw new IOException["Failed to delete " + file]; } }
Đệ quy tiêu chuẩn sử dụng NIO [kể từ Java 7]
Java 7 đã giới thiệu API cải tiến cho hoạt động I/O [còn được gọi là NIO]. Khi chúng tôi quyết định sử dụng nó, phương pháp đầu tiên có thể được thay đổi như sau
void deleteDirectoryRecursion[Path path] throws IOException { if [Files.isDirectory[path, LinkOption.NOFOLLOW_LINKS]] { try [DirectoryStream entries = Files.newDirectoryStream[path]] { for [Path entry : entries] { deleteDirectoryRecursion[entry]; } } } Files.delete[path]; }
Cây đi bộ [kể từ Java 7]
Ngoài ra, Java 7 đã giới thiệu phương thức mới Files. walkFileTree[] đi qua cây thư mục trong hệ thống tệp bằng cách sử dụng mẫu thiết kế của khách truy cập. Phương pháp mới này có thể dễ dàng được sử dụng để xóa đệ quy thư mục
void deleteDirectoryWalkTree[Path path] throws IOException { FileVisitor visitor = new SimpleFileVisitor[] { @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 { Files.delete[file]; return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory[Path dir, IOException exc] throws IOException { if [exc != null] { throw exc; } Files.delete[dir]; return FileVisitResult.CONTINUE; } }; Files.walkFileTree[path, visitor]; }
Luồng và NIO2 [kể từ Java 8]
Kể từ Java 8, chúng tôi có thể sử dụng Tệp. walk[] hoạt động như thế này theo tài liệu chính thức
Trả lại một Luồng được điền một cách lười biếng với Đường dẫn bằng cách đi bộ cây tệp bắt nguồn từ một tệp bắt đầu nhất định. Cây tệp được duyệt theo chiều sâu trước tiên, các phần tử trong luồng là các đối tượng Đường dẫn thu được như thể bằng cách giải quyết đường dẫn tương đối so với bắt đầu
Trước tiên, luồng phải được sắp xếp theo thứ tự ngược lại để tránh xóa thư mục không trống. Mã cuối cùng trông như thế này
void deleteDirectoryStream[Path path] throws IOException { Files.walk[path] .sorted[Comparator.reverseOrder[]] .map[Path::toFile] .forEach[File::delete]; }
Tuy nhiên, mã này có hai nhược điểm
- Luồng đang được sắp xếp để tất cả các phần tử luồng phải có mặt trong bộ nhớ cùng một lúc. Điều này có thể làm tăng đáng kể mức tiêu thụ bộ nhớ cho các cây thư mục sâu
- Không có xử lý lỗi vì giá trị trả về từ Tệp. xóa [] bị bỏ qua. Điều này có thể được cải thiện bằng cách sử dụng lambda tùy chỉnh bên trong forEach[]
Apache Commons IO
Cuối cùng, có một giải pháp đơn giản cho những người thiếu kiên nhẫn. Chỉ cần thêm phụ thuộc Maven
commons-io commons-io 2.6
và gọi phương thức duy nhất này
FileUtils.deleteDirectory[file];
Đó là tất cả
Phần kết luận
Tất cả các phương pháp trên nên thực hiện công việc. Cá nhân, tôi thích cái cuối cùng hơn vì nó đơn giản nhất để sử dụng. Mã nguồn có sẵn tại GitHub