Java держит блокировку файлов без видимой причины - PullRequest
11 голосов
/ 25 февраля 2009

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

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

ОБНОВЛЕНИЕ: пример кода FLAC удален, код работал, если я его изолировал.

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

ОБНОВЛЕНИЕ: я работаю с предположением, что отсутствует отсутствующий метод close () или close (), который не вызывается где-либо в моем коде или внешней библиотеке. Я просто не могу его найти!

Ответы [ 7 ]

6 голосов
/ 25 февраля 2009

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

3 голосов
/ 25 февраля 2009

Я предполагаю, что вы используете jFlac . Я скачал jFlac 1.3 и попробовал ваш пример кода на только что загруженном из Интернета архиве живой музыки. Для меня это сработало. Я даже контролировал его с помощью 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() и регистрировать ошибки, если при закрытии возникает исключение.

0 голосов
/ 30 апреля 2009

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

0 голосов
/ 01 марта 2009

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

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

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

0 голосов
/ 25 февраля 2009

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

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

0 голосов
/ 25 февраля 2009

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

у вас есть:

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

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

try
{
...code
}
finally
{
}


while (something)
   ;

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

Вы намеревались сделать это do {весь ваш код} while (ваше заявление 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 () для каких-либо потоков, записывающих в файл?

0 голосов
/ 25 февраля 2009

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

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

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

EDIT:

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

РЕДАКТИРОВАТЬ 2:

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...