Я пытаюсь найти способ удалить непустую директорию. Но все решения, которые я нашел, имели общую проблему - они не полностью удаляют непустую папку при определенных обстоятельствах, например, если она открыта в проводнике.
Эта проблема возникает не только при открытии в проводнике, нотакже в других случаях, которые я пока не смог определить. Но дело в том, что удаление не всегда работает правильно. Кажется, что Java не успевает обновить информацию каталога и думает, что папка не пуста, хотя все файлы в ней уже были удалены, потому что если выполнить код в режиме отладки или заставить поток засыпать хотя быЧерез 1 мс после каждого удаления папка всегда удаляется правильно.
Вот некоторые решения, которые я нашел:
// Using java.io.File
public static boolean deleteDirectory(File path) {
if (path.exists()) {
File[] files = path.listFiles();
if (files != null) {
for (File file : files) {
deleteDirectory(file);
}
}
Path p = path.toPath();
try {
Files.delete(p);
return true;
}
catch (IOException ex) {
ex.printStackTrace();
return false;
}
}
return true;
}
// Using java.nio.file.*
public static boolean deleteDirectory(Path path) {
try {
Files.walk(path)
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(file -> {
if (!file.delete()) throw new DeleteIOException(file);
});
}
catch (IOException ex) {
log.error("Ошибка удаления директории: " + path.toAbsolutePath(), ex);
return false;
}
catch (DeleteIOException ex) {
return false;
}
return true;
}
// Using NIO2 Java 7
public static boolean deleteDirectoryWalkTree(Path path) {
FileVisitor<Path> visitor = 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 {
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;
}
};
try {
Files.walkFileTree(path, visitor);
}
catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
// Using FileUtils from commons-io
public static boolean deleteDirectoryCommonsIO(File path) {
try {
FileUtils.deleteDirectory(path);
}
catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
// Using FileSystemUtils from Spring
public static boolean deleteDirectorySpring(Path path) {
try {
return FileSystemUtils.deleteRecursively(path);
}
catch (IOException e) {
e.printStackTrace();
return false;
}
}
Я использовал этот код для тестирования и воспроизведения проблемы. Я установил точку останова перед удалением и открыл в проводнике "BASE_TEST_DIRECTORY / 1 / s1". Все тесты не пройдены.
@BeforeEach
private void createAndTestDirectories() throws IOException {
String dir1 = "1";
String dir2 = "2";
String dir3 = "3";
String subDir1 = "s1";
String subDir2 = "s2";
String subDir3 = "s3";
String fileName = "file";
createDirectory(Paths.get(BASE_TEST_DIRECTORY));
createDirectory(Paths.get(BASE_TEST_DIRECTORY, dir1));
createDirectory(Paths.get(BASE_TEST_DIRECTORY, dir2));
createDirectory(Paths.get(BASE_TEST_DIRECTORY, dir3));
createDirectory(Paths.get(BASE_TEST_DIRECTORY, dir1, subDir1));
createDirectory(Paths.get(BASE_TEST_DIRECTORY, dir1, subDir2));
createDirectory(Paths.get(BASE_TEST_DIRECTORY, dir1, subDir3));
createFile(Paths.get(BASE_TEST_DIRECTORY, dir1, subDir1, fileName));
assertTrue(Files.exists(Paths.get(BASE_TEST_DIRECTORY)));
assertTrue(Files.exists(Paths.get(BASE_TEST_DIRECTORY, dir1, subDir1, fileName)));
}
@Test
public void deleteDirectoryPath_ExpectCleanDirectory() {
boolean result = DeleteDirectoryUtil.deleteDirectory(Paths.get(BASE_TEST_DIRECTORY));
assertTrue(result);
assertFalse(Files.exists(Paths.get(BASE_TEST_DIRECTORY)));
}
У меня есть такие ошибки:
java.nio.file.DirectoryNotEmptyException: target\ioTests\1
...
java.io.IOException: Unable to delete directory target\ioTests\1.
...
Любые предложения, чтобы решить эту проблему и не использовать Thread.sleep (1) ?
UPD
Проблема появляется в Windows 10. Я не тестировал на других ОС.
Проблема появляется не только если папка открыта в Проводнике,описанный случай с проводником - это самый простой способ воспроизвести его.
Иногда удаление не работает полностью во время нормального выполнения программы, когда в папке не происходит никаких процессов, поэтому я и задал этот вопрос. Иногда он полностью удаляется, а иногда нет.
Эта проблема возникает не только из-за проводника Windows, поскольку при удалении папки, в которой он находится, он удаляется успешно, и проводник пытается отобразить предыдущую папку, как будтоВы нажали Alt + Стрелка влево или Backspace. А также, как я описал выше, удаление работает нормально, даже если папка открыта в проводнике, если вы последовательно выполняете код в режиме отладки или вставляете этот код после каждого удаления:
try {
Thread.sleep(1);
}
catch (InterruptedException e) {
e.printStackTrace();
}
Другие решенияfrom org.apache.commons.io ( FileUtils.forceDelete (каталог) и FileDeleteStrategy.FORCE.delete (aFile) ), которые @Yasham, предложенные в комментариях, имеют ту же проблему.