Проверьте, был ли открытый файл удален после открытия в python

Можно ли проверить, был ли файл удален или воссоздан в python?

Например, если вы сделали open("file") в script, а затем, пока этот файл все еще открыт, вы выполняете rm file; touch file;, тогда script будет по-прежнему содержать ссылку на старый файл, хотя он уже удален.

Ответы

Ответ 1

Да. Используйте функцию os.stat(), чтобы проверить длину файла. Если длина равна нулю (или функция возвращает ошибку "Файл не найден" ), то кто-то удалил файл.

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

Почему? Поскольку новый файл не является файлом, который вы держите открытым. В двух словах файловые системы Unix имеют два уровня. Одним из них является запись в каталоге (то есть имя файла, размер файла, время модификации, указатель на данные), а второй уровень - данные файла.

Когда вы открываете файл, Unix использует это имя для поиска файлов. После этого он работает только на втором уровне - изменения в записи каталога не влияют на какие-либо открытые "дескрипторы файлов". Именно поэтому вы можете удалить запись в каталоге: ваша программа не использует ее.

Когда вы используете os.stat(), вы не смотрите на данные файла, а на запись каталога снова.

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

С отрицательной стороны вы не можете легко решить проблемы, подобные тем, которые у вас есть.

Ответ 2

Вы должны fstat описать файл для открытого файла.

>>> import os
>>> f = open("testdv.py")
>>> os.fstat(f.fileno())
posix.stat_result(st_mode=33188, st_ino=1508053, st_dev=65027L, st_nlink=1, st_uid=1000, st_gid=1000, st_size=1107, st_atime=1349180541, st_mtime=1349180540, st_ctime=1349180540)
>>> os.fstat(f.fileno()).st_nlink
1

Хорошо, этот файл имеет одну ссылку, поэтому одно имя в файловой системе. Теперь удалите его:

>>> os.unlink("testdv.py")
>>> os.fstat(f.fileno()).st_nlink
0

Больше никаких ссылок, поэтому у нас есть "анонимный файл", который поддерживается только пока мы его открываем. Создание нового файла с тем же именем не влияет на старый файл:

>>> g = open("testdv.py", "w")
>>> os.fstat(g.fileno()).st_nlink
1
>>> os.fstat(f.fileno()).st_nlink
0

Конечно, st_nlink может иногда быть >1 изначально, поэтому проверка того, что для нуля не является полностью надежной (хотя в контролируемой настройке она может быть достаточно хорошей). Вместо этого вы можете проверить, является ли файл на пути, который вы изначально открыли, тот же, что у вас есть файловый дескриптор, путем сравнения результатов stat:

>>> os.stat("testdv.py") == os.fstat(f.fileno())
False
>>> os.stat("testdv.py") == os.fstat(g.fileno())
True

(И если вы хотите, чтобы это было на 100% правильно, вы должны сравнивать только поля st_dev и st_ino в результатах stat, так как другие поля и st_atime в частности могут меняться между вызовы.)

Ответ 3

Да - вы можете использовать средство inotify для проверки изменений файлов и т.д. Для этого также есть Python привязка. Используя inotify, вы можете просматривать файлы или каталоги для активации файловой системы. Из руководства можно обнаружить следующие события:

IN_ACCESS         File was accessed (read) (*).
IN_ATTRIB         Metadata changed, e.g., permissions, timestamps, extended attributes, link count (since Linux 2.6.25), UID, GID, etc. (*).
IN_CLOSE_WRITE    File opened for writing was closed (*).
IN_CLOSE_NOWRITE  File not opened for writing was closed (*).
IN_CREATE         File/directory created in watched directory (*).
IN_DELETE         File/directory deleted from watched directory (*).
IN_DELETE_SELF    Watched file/directory was itself deleted.
IN_MODIFY         File was modified (*).
IN_MOVE_SELF      Watched file/directory was itself moved.
IN_MOVED_FROM     File moved out of watched directory (*).
IN_MOVED_TO       File moved into watched directory (*).
IN_OPEN           File was opened (*).

Отсюда вы можете самостоятельно решить проблему, но я думаю, что вы получите общую идею. Конечно, это может работать только на Linux, но из вашего вопроса я предполагаю, что вы его используете (ссылки на rm и touch).