RandomAccessFile Висячий указатель

Я использую объект RandomAccessFile для доступа к файлам с

RandomAccessFile file = new RandomAccessFile(path, "r");

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

file.seek(...); 

or a

file.readLine()

никакого исключения не запускается, у меня нет никакого исключения.

Можно ли сделать исключение для Dangling Pointer, если этот файл был удален с диска?

Есть ли другой способ определить недоступность файла?


person Alberto acepsut    schedule 17.06.2014    source источник


Ответы (2)


РЕДАКТИРОВАТЬ: точность для Windows (спасибо pingw33n)

Совершенно нормально, что вы не получаете Exception, когда:

  • вы открываете файл
  • вы или кто-то другой удаляет файл
  • вы по-прежнему имеете доступ к файлу, читаете его содержимое перед удалением или записываете в него

На самом деле удаление файла ничего не делает с самим файлом. То, что удаляется, является записью в каталоге. И файл будет фактически уничтожен (и секторы, которые он использует на диске, будут освобождены) только тогда, когда:

  • больше никакие записи каталога не указывают на него
  • никакие файловые дескрипторы не удерживают его открытым

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

Конечно, вы можете сделать то, что предлагает merlin2011, то есть проверить наличие файла через его путь. Но вы должны знать, что файл удаляется, а затем создается снова, путь (который использовался для открытия файла) присутствует, но указывает на совершенно другой объект.

Поэтому, если вам действительно нужно, чтобы файл действительно отражал содержимое каталога, вы не можете держать его открытым и должны открывать его при каждом доступе... Это нечестный вариант, который вы все равно можете:

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

Это верно для всех обычных файловых систем, всех систем Linux или других Unix, таких как системы, NTFS и т. д. Я не уверен, что это верно для более старых, таких как CPM или FAT, но в настоящее время они больше не используются в производстве. :-). Но в Windows не должно быть возможности удалить файл, открытый в настоящее время в приложении Java.

Чтобы точно ответить вам на 2 вопроса:

  • ваш указатель не болтается, но все еще указывает на реальный файл (даже если никто другой его не видит)
  • Исключение будет выдано в случае недоступности файла (физическое повреждение диска или соединений, ошибки файловой системы и т.д.). Но если только запись была удалена, файл все еще доступен
person Serge Ballesta    schedule 17.06.2014
comment
В контексте Java все это относится к * nix только потому, что для Windows в Java нет стандартного способа установить FILE_SHARE_DELETE для создаваемых/открываемых файлов, чтобы их нельзя было удалить в обычном режиме. - person pingw33n; 18.06.2014
comment
Спасибо Serge Ballesta и Merlin2011 за вашу помощь. Последний вопрос: я проверяю, если file.readLine() == null, и если это так, я закрываю и снова открываю файл. Это правильная процедура? - person Alberto acepsut; 18.06.2014
comment
Нет, потому что нет никакой связи между тем, что файл был удален (запись удалена) и вашими собственными доступами. - person Serge Ballesta; 18.06.2014
comment
@Serge Ballesta check file.readLine() == null, кажется, работает в Linux, чтобы идентифицировать удаленный файл (ранее открытый) - person famedoro; 18.06.2014

На ваш вопрос есть два ответа.

  • На основе Javadoc вы должны получить IOException, если какой-либо байт не может быть прочитан по какой-либо причине.

Если какой-либо байт не может быть прочитан по какой-либо причине, кроме конца файла, генерируется исключение IOException, отличное от EOFException. В частности, исключение IOException может быть вызвано, если поток был закрыт.

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

    File f = new File(filePathString);
    if(f.exists() && !f.isDirectory()) { /* do something */ }
    
person merlin2011    schedule 17.06.2014
comment
Файл уже существует, когда новый RandomAccessFile(path, r); сделано, он будет удален позже. - person Alberto acepsut; 17.06.2014
comment
@Albertoacepsut, моя интерпретация документа заключается в том, что если файл будет удален позже, а затем вы попытаетесь прочитать, он выдаст IOException. (Предполагается, что вы пытаетесь прочитать байт, не буферизованный в памяти). - person merlin2011; 17.06.2014
comment
@ merlin2011 ваша интерпретация логична, но неверна. Подробности смотрите в моем ответе. - person Serge Ballesta; 18.06.2014
comment
@SergeBallesta, я исправлен. Я оставлю этот ответ для потомков, так как я думаю, что это достаточно распространенное недоразумение. - person merlin2011; 18.06.2014