Проверьте, был ли открытый файл удален после открытия в 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
).