Подтвердить что ты не робот

Java сохраняет блокировку файлов без видимых причин

Несмотря на закрытие потоков в предложениях finally, я, похоже, постоянно сталкивается с проблемами при использовании Java. File.delete() не удаляет файлы, Windows Explorer тоже выходит из строя. Иногда Running System.gc() помогает, но ничего, кроме завершения работы виртуальной машины, постоянно поддерживается, и это не вариант.

Есть ли у кого-нибудь другие идеи, которые я мог бы попробовать? Я использую Java 1.6 в Windows XP.

UPDATE: образец кода FLAC удален, код работал, если я его изолировал.

UPDATE: Дополнительная информация, это происходит в Apache Tomcat, Commons FileUpload используется для загрузки файла и может быть виновником, также я использую Runtime.exec() для выполнения LAME в отдельном процессе для кодирования файла, но это вряд ли вызовет это поскольку ProcessExplorer четко указывает, что java.exe имеет блокировку RW в файле, а LAME прекращает работу.

UPDATE: Я работаю с предположением, что есть недостающие close() или close(), которые не вызываются где-то в моем коде или внешней библиотеке. Я просто не могу его найти!

4b9b3361

Ответ 1

Код, который вы опубликовали, выглядит хорошо - он не должен вызывать проблем, которые вы описываете. Я понимаю, что вы опубликовали только часть кода, который у вас есть, - можете ли вы попробовать извлечь только эту часть в отдельную программу, запустить ее и посмотреть, не исчезла ли проблема? Я предполагаю, что в коде есть другое место, которое делает new FileInputStream(path); и не закрывает поток должным образом. Возможно, вы просто видите результаты здесь, когда пытаетесь удалить файл.

Ответ 2

Я предполагаю, что вы используете jFlac. Я загрузил jFlac 1.3 и попробовал свой образец кода на flac, недавно загруженном из интернет-живого музыкального архива. Для меня это сработало. Я даже отслеживал это с помощью ProcessExplorer и видел, как открываются и затем отпираются дескрипторы файлов. Является ли ваш тестовый код таким же простым, как то, что вы нам дали, или это упрощенная версия вашего кода? Для меня, когда был вызван метод close(), дескриптор был выпущен, и файл впоследствии был успешно удален.

Попробуйте изменить свой бесконечный цикл:

File toDelete = new File(path);
if (!toDelete.delete()) {
  System.out.println("Could not delete " + path);
  System.out.println("Does it exist? " + toDelete.exists());
}

или если вы хотите продолжать цикл, то поставьте 1-й сон между попытками удалить файл. Я попробовал это с JDK6 на WinXP Pro.

Не забудьте поставить попытку/уловить ваши ошибки close() и log, если закрытие вызывает исключение.

Ответ 3

Убедитесь, что у вас есть ваши закрытые вызовы в блоке finally, а не в блоке try. Если нет try/finally, потому что метод генерирует исключение, добавьте try/finally и поставьте туда закрытие.

Посмотрите на Диспетчер задач Windows. Для процессов добавьте столбец "Ручки" (в меню "Вид" ). Посмотрите, не перестают ли ручки продолжать движение.

Используйте профилировщик, чтобы увидеть, есть ли у вас объекты Stream/Reader/Writer, которые вы не думаете, что должны иметь.

EDIT:

Спасибо, что опубликовали код..., чтобы увидеть его. Одна вещь - ваши тесные методы не гарантированы и гарантированно выполнить - первая закрытие может забросить, а затем вторая не будет работать.

ИЗМЕНИТЬ 2:

final WavWriter wavWriter = новый WavWriter (os); Декодер LACDecoder = новый FLACDecoder (есть);

Вышеуказанные две строки приведут к тому, что стромы будут храниться в переменных экземпляра предположительно. В качестве теста посмотрите, можете ли вы установить ссылки потока на null после вызова decoder.decode() (возможно, сделать метод decoder.cleanup()). Посмотрите, что проблема с удержанием на закрытых потоках.

Кроме того, выполняется ли какая-либо упаковка потоков, переданных в указанные выше конструкторы? Если это возможно, вам придется закрыть потоки через обертку.

Ответ 4

Разве это не пустой цикл while?

у вас есть:

try
{
...code
}
finally
{
}
while (something);

введите там пробелы, и на самом деле у вас есть:

try
{
...code
}
finally
{
}


while (something)
   ;

ваш цикл while не связан с вашим try/finally. если ваш исходный оператор try не работает, и файл не создается, то цикл while никогда не будет завершен, потому что try/finally никогда не будет выполняться во второй раз.

Вы намеревались сделать так, чтобы сделать {весь ваш код} в то время как (ваш оператор while)? потому что это не то, что у вас есть.

ИЗМЕНИТЬ, чтобы уточнить: мое предложение состояло бы в том, чтобы изменить цикл while, чтобы узнать больше о том, почему он не может удалить:

while (!file.delete())
{
    if (!file.exists())
        break; // the file doesn't even exist, of course delete will fail

    if (!file.canRead())
        break; // the file isn't readable, delete will fail

    if (!file.canWrite())
        break; // the file isn't writable, delete will fail
}

потому что, если удаление не удастся один раз, его просто будет терпеть неудачу снова и снова, конечно, это будет там. вы не изменяете состояние файла в цикле.

Теперь, когда вы добавили другую информацию, такую ​​как Tomcat и т.д., это проблема с разрешениями? вы пытаетесь записать в файл, который пользователь tomcat работает как (никто?) vm не может создать? или удалить файл, который не может удалить процесс tomcat?

Если обработчик процессов /etc говорит, что у java есть блокировка файла, то у него все еще есть открытый поток. кто-то, возможно, неправильно вызвал close() для любых потоков, которые записываются в файл?

Ответ 5

Ваш образец кода обязательно должен работать. Фактически я запускал его на Java 1.6/Vista с jflac 1.3, и исходный файл был удален, без каких-либо циклов.

Я предполагаю, что в вашем случае другой процесс держит файл открытым, возможно, индексом поиска на рабочем столе или антивирусом. Вы можете procexp, чтобы найти, какой процесс фактически держит файл.

Ответ 6

Если у вас нет подсказок и идей: в cygwin, cd для вашего javaroot и выполните что-то вроде:

find . -name '*.java' -print0 | xargs -0 grep "new.*new.*putStream"

Он может предоставить несколько подозреваемых...

Ответ 7

Еще одна вещь, которую нужно попробовать, поскольку вы используете Tomcat - в своем дескрипторе контекста (обычно Tomcat/conf/Catalina/localhost/your-context.xml), вы можете установить antiResourceLocking=true, который предназначен для "предотвращения блокировки ресурсов в Windows". По умолчанию для этого (если вы не укажете) значение false. Стоит попробовать.