Python:锁定目录

Posted

技术标签:

【中文标题】Python:锁定目录【英文标题】:Python: Lock directory 【发布时间】:2019-03-09 15:54:40 【问题描述】:

AFAIK 此代码可用于锁定目录:

class LockDirectory(object):
    def __init__(self, directory):
        assert os.path.exists(directory)
        self.directory = directory

    def __enter__(self):
        self.dir_fd = os.open(self.directory, os.O_RDONLY)
        try:
            fcntl.flock(self.dir_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
        except IOError as ex:
            if ex.errno != errno.EAGAIN:
                raise
            raise Exception('Somebody else is locking %r - quitting.' % self.directory)

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.dir_fd.close()

但是根据这个问题的答案锁定一个目录是不可能的:Python: Lock a directory

上面的代码有什么问题?

我只需要支持当前的linux版本。没有 Windows、Mac 或其他 unix。

【问题讨论】:

你自己的python进程是唯一对目录进行操作的候选吗? @FlyingTeller 有另一个进程将文件放入此目录,但这不需要锁定。只有消耗数据的python脚本需要锁定。 如果它在同一个进程中,为什么不使用“is_running”标志,这样如果当前进程没有完成,你就不会触发下一个进程? 问题是“如何锁定目录?”答案是“你不能,创建一个象征着锁定目录的文件” @Jean-FrançoisFabre Cron 每 N 分钟启动一次进程。您建议使用“is_running”标志。这就是为什么我要锁定脚本运行的目录。 【参考方案1】:

我稍微修改一下你的代码,像大多数上下文管理一样添加return self,然后使用dup(),第二个上下文管理将失败。解决方案很简单,取消注释fcntl.flock(self.dir_fd,fcntl.LOCK_UN)

用于打开文件的模式与flock无关。

而且你不能在 NFS 上蜂拥而至。

import os
import fcntl
import time
class LockDirectory(object):
    def __init__(self, directory):
        assert os.path.exists(directory)
        self.directory = directory

    def __enter__(self):
        self.dir_fd = os.open(self.directory, os.O_RDONLY)
        try:
            fcntl.flock(self.dir_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
        except IOError as ex:             
            raise Exception('Somebody else is locking %r - quitting.' % self.directory)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        # fcntl.flock(self.dir_fd,fcntl.LOCK_UN)
        os.close(self.dir_fd)

def main():
    with LockDirectory("test") as lock:
        newfd = os.dup(lock.dir_fd)
    with LockDirectory("test") as lock2:
        pass

if __name__ == '__main__':
    main()

【讨论】:

太棒了。有没有人从这个在 github+pypi 上制作一个小 Python 库很有趣?【参考方案2】:

如果您只需要一个 read 锁,那么您的代码中只有一个小错误。在目录上获得读锁是完全可行的。

您需要更改您的__exit__ 函数以使用os.close() 来关闭文件描述符;文件描述符只是一个整数,整数没有.close() 方法:

def __exit__(self, exc_type, exc_val, exc_tb):
    os.close(self.dir_fd)

对于那些认为你做不到的人来说,通常的困惑是那些尝试过 open() 函数的人。 Python 不会让您使用该函数打开目录节点,因为为目录创建 Python 文件对象是没有意义的。或者您可能假设您希望操作系统通过锁定强制访问目录(而不是一组协作进程同意在尝试访问之前首先获得的建议锁定)。

所以,不,如果您想要的只是一个咨询锁,那么代码没有任何问题,并且仅适用于 Linux 就可以了。

我会从代码中删除directory 的区别。该锁将在您具有读取权限的任何路径上工作。它不是目录独有的。

锁定目录的缺点是它没有给您一个存储锁定元数据的地方。虽然lsof 可以为您提供锁的当前所有者的 PID,但您可能希望与锁通信一些其他信息以帮助排除故障或自动开锁。 .lock 文件或符号链接可让您记录其他信息。例如,Mercurial 将使用主机名、PID 命名空间标识符(仅限 Linux)和目标名称中的 PID 创建一个符号链接;您可以原子地创建这样的符号链接,而将数据写入文件需要在临时名称下创建一个文件,然后重命名。

【讨论】:

【参考方案3】:

我在这里找到了答案:Python: Lock directory

可以用这个来锁定目录:

fcntl.flock(self.dir_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)

当然这是一个锁,玩这个游戏的每个代码都需要先检查。

AFAIK 这被称为“咨询锁”。

【讨论】:

你不需要再保留这个了。我合并了问题。请不要再问这样的重复问题。 @YvetteColomb 如果我再次这样做会怎样? 这不是可能发生的最糟糕的事情,这是我们不鼓励的事情。它为人们不得不关闭它们创造了更多的工作。如果这是一个持续的习惯,它可能会导致纪律处分,但这是在极少数和持续存在的情况下。【参考方案4】:

我建议您使用简单的锁定文件。正如评论 (How to lock a directory between python processes in linux?) 中的问题所暗示的那样,目录 没有锁定机制,而不是文件。 锁定文件在 Linux 上左右使用,它们非常透明且易于调试,所以我就这么做了。 不过,我正在等待接受挑战!

【讨论】:

目录支持咨询锁定就好了,其他答案是完全错误的。你所需要的只是一个文件句柄,低级的os.open() 调用可以让你打开一个目录文件句柄就好了。

以上是关于Python:锁定目录的主要内容,如果未能解决你的问题,请参考以下文章

创建ftp用户,锁定访问目录

vsftp 锁定用户目录

c# savefiledialog 锁定到特定目录? [复制]

如何在Unix中为shell脚本锁定目录[重复]

201207:SVN提示文件被锁定不能更新-啥是k8s

ssh锁定(chroot)普通账号的活动目录