Java File.delete () не удаляет все файлы

У меня есть следующий код Java, который выполняет итерацию по всем файлам в каталоге и удаляет их.

for(File file : tmpDir.listFiles())
{
    file.delete();
}

Однако он не удаляет все файлы. Некоторые, обычно 20-30 человек из пары тысяч, остаются позади, когда я это делаю. Можно ли это исправить, или я наткнулся на какое-то Java-вуду, которое лучше не трогать?


person user1049697    schedule 02.11.2013    source источник
comment
Возможно, у вас нет разрешения на удаление файла. Или он заблокирован, или его воссоздают, или что-то еще. Проверьте возвращаемое значение, чтобы узнать, было ли удаление успешным или нет). Также учтите, что каталоги должны быть пустыми, чтобы их можно было удалить.   -  person Stefano Sanfilippo    schedule 02.11.2013
comment
какая-нибудь ошибка? какие файлы не удаляются?   -  person WhileTrueSleep    schedule 02.11.2013
comment
Вы уверены, что можете удалить все файлы вручную? Возможно, некоторые из них используются другими программами. Попробуйте перехватить исключение: Обратите внимание, что класс Files определяет метод удаления, который генерирует исключение IOException, когда файл не может быть удален. Это полезно для отчетов об ошибках и для диагностики, почему файл не может быть удален.   -  person Alexis C.    schedule 02.11.2013
comment
Убедитесь, что для файлов, которые вы пытаетесь удалить, не открыты никакие обработчики файлов.   -  person Aakash Goyal    schedule 02.11.2013
comment
Нет, у меня есть права и все такое. Это набор файлов, которые я создаю, обрабатываю и снова удаляю. Но некоторые файлы остаются и не удаляются вместе со своими собратьями.   -  person user1049697    schedule 02.11.2013
comment
@ZouZou в Java 1.6 исключений не возникает, возможно, OP использует более старый JDK.   -  person Stefano Sanfilippo    schedule 02.11.2013
comment
@StefanoSanfilippo OP использует File.delete(), а не Files.delete(...) из пакета NIO2.   -  person Tom G    schedule 02.11.2013
comment
@TomG ну да, думаю, я знаю ... Какая связь между моими комментариями и NIO2?   -  person Stefano Sanfilippo    schedule 02.11.2013


Ответы (3)


Он возвращает значение boolean, вы должны это проверить. Из JavaDoc:

Возвращает: true тогда и только тогда, когда файл или каталог были успешно удалены; ложь иначе

Вам следует проверить значение возврата и принять меры.

Если он возвращает false, вполне возможно, что у вас нет разрешения на удаление файла.

В этом случае вы можете проверить, доступно ли приложение для записи в файл, и, если нет, попытаться сделать его доступным для записи - снова возвращается boolean. В случае успеха вы можете попробовать удалить еще раз.

Вы можете использовать служебный метод:

private void deleteFile(final File f) throws IOException {
    if (f.delete()) {
        return;
    }
    if (!f.canWrite() && !f.setWritable(true)) {
        throw new IOException("No write permissions on file '" + f + "' and cannot set writeable.");
    }
    if (!f.delete()) {
        throw new IOException("Failed to delete file '" + f + "' even after setting writeable; file may be locked.");
    }
}

Я бы также прислушался к их совету в JavaDoc:

Обратите внимание, что класс Files определяет метод удаления, который генерирует исключение IOException, когда файл не может быть удален. Это полезно для отчетов об ошибках и для диагностики, почему файл не может быть удален.

При условии, что вы используете Java 7 то есть. Этот метод вызывает ряд исключений, с которыми вы можете справиться:

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

Пример взят из учебной страницы Oracle.

person Boris the Spider    schedule 02.11.2013
comment
Я не понимаю, почему люди голосуют за это. Он не отвечает на вопрос ОП, он лучше подходит для комментария. - person Stefano Sanfilippo; 02.11.2013
comment
оказывается примерно на полпути - person clwhisk; 02.11.2013
comment
Я пробовал это, но он никогда не возвращает false, поэтому при удалении файла ошибок нет. Кажется, что файлы не видны, когда цикл повторяется и удаляет их. - person user1049697; 02.11.2013
comment
Вы пробовали распечатать имена файлов, перебираемых в регистраторе, а затем искать проблемные? Вы пытались добавить точку останова после вызова удаления, чтобы увидеть, воссоздан ли файл чем-то еще? - person Boris the Spider; 02.11.2013
comment
@BoristheSpider Я вышел из программы сразу после попытки удаления файлов, и некоторые из них еще остались. Если я запускаю программу снова и снова с одним и тем же вводом, для каждой итерации остаются разные файлы, поэтому не существует системы для того, что остается. - person user1049697; 02.11.2013
comment
@BoristheSpider Я пробовал ваш код, и он выдает ошибку Failed to delete file даже после установки writeable; файл может быть заблокирован. Получается, что файлы загружаются другим процессом даже после того, как он их обработал и завершил работу. - person user1049697; 04.11.2013
comment
Я бы попробовал воспользоваться методом Files - ошибки намного информативнее. Однако я думаю, что вы, вероятно, правы в своих предположениях о том, что файл заблокирован. - person Boris the Spider; 04.11.2013
comment
@BoristheSpider Да, используя метод Files, мне говорят, что он заблокирован процессом. Но странно то, что все файлы в папке используются одним и тем же процессом, но только некоторые из них заблокированы. И процесс должен быть мертв после их использования, так что я даже не знаю, как это может быть зомби, схватившим их. - person user1049697; 05.11.2013
comment
Наиболее вероятное объяснение заключается в том, что вы не закрываете ресурс где-то / иногда. InputStream или OutputStream не закрывается, поэтому ресурсы не высвобождаются. Если это происходит случайно, то это может быть гоночная опасность (надеюсь, ради вашего здравомыслия) ... - person Boris the Spider; 05.11.2013
comment
@BoristheSpider Я обнаружил ошибку. Запуск System.gc(); перед удалением позволяет удалять файлы. - person user1049697; 05.11.2013

Принудительный запуск сборщика мусора с использованием System.gc(); сделал все файлы доступными для удаления.

person user1049697    schedule 07.11.2013
comment
Это решение, но можно ли это делать? - person Mafro34; 10.05.2014
comment
У меня была эта проблема, пока я не нашел файл, который забыл закрыть. Как обычно, если я обнаруживаю, что мне нужно собирать мусор, чтобы добиться желаемого поведения, у меня происходит утечка ресурсов. - person Jeff Learman; 04.05.2015
comment
Но вызов System.gc (); не гарантирует, что сборка мусора произойдет мгновенно. - person Sreekanth Karumanaghat; 21.10.2016

Убедитесь, что у вас нет открытого потока, такого как BufferedReader / Writer, FileReader / Writer и т. Д. Сначала закройте их, тогда вы сможете удалить файл. Еще один момент, например. если вы открываете BufferedReader через другой читатель, например FileReader, вы должны закрыть оба читателя по отдельности.

Итак, вместо этого:

BufferedReader reader = new BufferedReader(new FileReader(new File(filePath)););

сделай это:

BufferedReader bufferedReader = null;
FileReader fileReader = null;

try{
    fileReader = new FileReader(readFile);
    bufferedReader = new BufferedReader(fileReader);

}catch{...}

...

try {
    fileReader.close();
    bufferedReader .close();
    readFile.delete();
} catch (IOException e) {
    e.printStackTrace();
}
person Melis    schedule 17.11.2017
comment
Это неправильно, см. Здесь: Мне нужно закрыть () как FileReader, так и BufferedReader? - person Max Vollmer; 25.06.2019