Вопрос-Ответ

Locking a file in Python

Блокировка файла в Python

Мне нужно заблокировать файл для записи на Python. Доступ к нему будет осуществляться из нескольких процессов Python одновременно. Я нашел несколько решений в Интернете, но большинство из них не подходят для моих целей, поскольку часто они основаны только на Unix или Windows.

Переведено автоматически
Ответ 1

Хорошо, в итоге я перешел к написанному мной коду здесь, на моем сайте ссылка недоступна, смотрите на archive.org (также доступна на GitHub). Я могу использовать ее следующим образом:

from filelock import FileLock

with FileLock("myfile.txt.lock"):
# work with the file as it is now locked
print("Lock acquired.")
Ответ 2

Другие решения ссылаются на множество внешних баз кода. Если вы предпочитаете сделать это самостоятельно, вот некоторый код для кроссплатформенного решения, которое использует соответствующие инструменты блокировки файлов в системах Linux / DOS.

try:
# Posix based file locking (Linux, Ubuntu, MacOS, etc.)
# Only allows locking on writable files, might cause
# strange results for reading.
import fcntl, os
def lock_file(f):
if f.writable(): fcntl.lockf(f, fcntl.LOCK_EX)
def unlock_file(f):
if f.writable(): fcntl.lockf(f, fcntl.LOCK_UN)
except ModuleNotFoundError:
# Windows file locking
import msvcrt, os
def file_size(f):
return os.path.getsize( os.path.realpath(f.name) )
def lock_file(f):
msvcrt.locking(f.fileno(), msvcrt.LK_RLCK, file_size(f))
def unlock_file(f):
msvcrt.locking(f.fileno(), msvcrt.LK_UNLCK, file_size(f))


# Class for ensuring that all file operations are atomic, treat
# initialization like a standard call to 'open' that happens to be atomic.
# This file opener *must* be used in a "with" block.
class AtomicOpen:
# Open the file with arguments provided by user. Then acquire
# a lock on that file object (WARNING: Advisory locking).
def __init__(self, path, *args, **kwargs):
# Open the file and acquire a lock on the file before operating
self.file = open(path,*args, **kwargs)
# Lock the opened file
lock_file(self.file)

# Return the opened file object (knowing a lock has been obtained).
def __enter__(self, *args, **kwargs): return self.file

# Unlock the file and close the file object.
def __exit__(self, exc_type=None, exc_value=None, traceback=None):
# Flush to make sure all buffered contents are written to file.
self.file.flush()
os.fsync(self.file.fileno())
# Release the lock on the file.
unlock_file(self.file)
self.file.close()
# Handle exceptions that may have come up during execution, by
# default any exceptions are raised to the user.
if (exc_type != None): return False
else: return True

Теперь, AtomicOpen может использоваться в with блоке, где обычно используется open оператор.

ПРЕДУПРЕЖДЕНИЯ:


  • Если запуск в Windows и Python завершается сбоем перед вызовом exit, я не уверен, каким будет поведение блокировки.

  • Представленная здесь блокировка носит рекомендательный, а не абсолютный характер. Все потенциально конкурирующие процессы должны использовать класс "AtomicOpen".

  • По состоянию на (9 ноября 2020 г.) этот код блокирует только доступные для записи файлы в системах Posix. В какой-то момент после публикации и до этой даты стало незаконным использовать fcntl.lock для файлов, доступных только для чтения.

Ответ 3

There is a cross-platform file locking module here: Portalocker

Although as Kevin says, writing to a file from multiple processes at once is something you want to avoid if at all possible.

If you can shoehorn your problem into a database, you could use SQLite. It supports concurrent access and handles its own locking.

Ответ 4

I have been looking at several solutions to do that and my choice has been
oslo.concurrency

It's powerful and relatively well documented. It's based on fasteners.

Other solutions:

python