Как диагностировать File.delete (), возвращая false / находить незакрытые потоки? - PullRequest
13 голосов
/ 24 января 2010

Я работаю с сторонней библиотекой манипуляции JPEG / EXIF ​​( Mediautil ), которая вызывает у меня некоторые головные боли. Я хочу изменить данные EXIF ​​изображения. Для этого мне нужно записать обновленную версию во временный файл, удалить оригинал, а затем переименовать временный файл с исходным именем.

Моя проблема в том, что вызов File.delete() завершается неудачно и возвращает false, предположительно потому, что библиотека все еще каким-то образом открыла его - но я сделал все, что смог найти в API, чтобы закрыть все потоки. Еще хуже: проблема, кажется, зависит от времени, и модульные тесты, где это происходит, иногда терпят неудачу, а иногда нет - но код не многопоточный.

Как ни странно, есть один вызов библиотеки, который устраняет проблему, но он также удаляет миниатюру EXIF, чего я на самом деле не хочу. И, глядя на код, я абсолютно не вижу, где он закрывает какие-либо потоки, которые в противном случае могли бы остаться открытыми.

Есть идеи, как решить эту проблему?

Edit: Это на Windows XP, Java 6. И еще одна вещь: я обнаружил, что если я вызываю System.gc() перед вызовом File.delete(), это работает - возможно потому, что это вызывает какой-то финализатор. Так что это определенно кажется незамеченным потоком.

Ответы [ 4 ]

5 голосов
/ 25 января 2010

Я хотел бы помочь с отладчиком здесь.Быстрый просмотр материала java.io показывает, что единственный вероятный кандидат finalize() находится в FileOutputStream.Поэтому установите точку останова, запустите вашу программу и попробуйте получить System.gc(), чтобы вызвать FileOutputStream.finalize() для освобождения вашего потока.Это должно дать вам ответ относительно того, является ли это вашей проблемой.

Как только вы сможете воспроизвести это, вам нужно начать сопоставлять экземпляры FileOutputStream с их завершением.Хороший отладчик предоставит вам внутренние идентификаторы объектов JVM для каждого объекта, поэтому, если вы сможете отслеживать OID по мере их создания и отслеживать их по завершении, то, надеюсь, вы сможете связать вызов ключа с finalizeс определенным вызовом new new FileOutputStream.

Возможно, это будет длинный улов, в зависимости от сложности вашего приложения.

1 голос
/ 18 ноября 2014

Если вы используете FileOutputStream, его закрытие явно разрешает удаление файла.

например. вместо:

File myFile = new File("test.txt");
myCustomStreamProcess(new FileOutputStream(myFile));
boolean test = myFile.delete(); //May return false

вы должны сделать:

File myFile = new File("test.txt");
FileOutputStream fos = new FileOutputStream(myFile);
myCustomStreamProcess(fos);
fos.close(); //Allow the document to be deleted afterwards
boolean test = myFile.delete(); //Should always return true
0 голосов
/ 25 января 2010

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

Я думаю, вы могли бы определить настоящую проблему; то есть используемый вами API пропускает дескрипторы открытых файлов.

Поскольку это библиотека с открытым исходным кодом, которую вы используете, у вас есть доступ к исходному коду. Таким образом, вы должны быть в состоянии подтвердить это, и при необходимости исправить это для себя. И чтобы быть хорошим гражданином, внесите свой вклад в проект, отправив патч.

0 голосов
/ 25 января 2010

Почему бы вам не переименовать файл до того, как библиотека откроет его? Затем, возможно, используйте Java File.deleteOnExit (), чтобы удалить переименованный файл. Например:

 File jpeg = new File("image.jpg");
 File temp = new File(jpeg + ".temp.jpg");
 jpg.renameTo(temp);
 SomeObj result = exifLibrary(temp); // or exifLibrary(new FileInputStream(temp);
 OutputStream jpegStream = new FileOutputStream(jpeg);
 output.write(result.bytes();
 output.close();
 temp.deleteOnExit();
 temp.delete();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...