如何在Python中排除可能正在使用或被复制的文件?

2 投票
3 回答
1099 浏览
提问于 2025-04-16 06:38

我刚开始学Python,所以可能这个问题有简单的解决办法。

在我家,有三台电脑和这个情况有关: - 文件服务器(运行Linux) - 我的主电脑(运行Windows) - 女朋友的MacBook Pro

我的文件服务器上装的是Ubuntu和Samba。我安装了Python 3.1,并且我的代码也是用3.1写的。

我创建了一个守护进程,它会检查上传目录中是否有符合特定模式的文件。如果找到这样的文件,它会重命名并把它移动到另一个位置,另一个驱动器上。它还会重新设置文件的拥有者、组和权限。所有这些都运行得很好。这个过程每分钟执行一次。

如果我从我的主电脑(运行Windows)复制文件,这个过程总是能正常工作。(我觉得Windows在复制文件时会锁定文件——我可能错了。)

但如果我女朋友复制文件,守护进程会在复制完成之前就检测到文件,这样就会出现问题。(会生成带下划线的文件,权限设置不正确,有时文件会被放到正确的位置。)

我猜她的MacBook在复制文件时不会锁定文件。我也可能是错的。

我需要的是一种方法,能够排除那些正在使用或正在创建的文件。

作为参考,我用来查找文件的方法是:

# _GetFileListing(filter)
# Description: Gets a list of relevant files based on the filter
#
# Parameters: filter - a compiled regex query
# Retruns:
#   Nothing. It populates self.fileList
def _GetFileListing(self, filter):
    self.fileList = []
    for file in os.listdir(self.dir):
        filterMatch = filter.search(file)
        filepath = os.path.join(self.dir, file)

        if os.path.isfile(filepath) and filterMatch != None:
            self.fileList.append(filepath)

注意,这些都在一个类里面。

我用来处理文件的方法是:

# _ArchiveFile(filepath, outpath)
# Description: Renames/Moves the file to outpath and re-writes the file permissions to the permissions used for
#   the output directory. self.mask, self.group, and self.owner for the actual values.
#
# Parameters: filepath - path to the file
#             outpath - path to the file to output
def _ArchiveFile(self, filepath, outpath):
    dir,filename,filetype = self._SplitDirectoryAndFile(outpath)

    try:
        os.makedirs(dir, self.mask)
    except OSError:
        #Do Nothing!
        dir = dir

    uid = pwd.getpwnam(self.owner)[2]
    gid = grp.getgrnam(self.group)[2]
    #os.rename(filepath, outpath)
    shutil.move(filepath, outpath)
    os.chmod(outpath, self.mask)
    os.chown(outpath, uid, gid)

我已经停止使用os.rename,因为当我开始把文件移动到不同的驱动器时,它似乎就不再工作了。

简而言之: 我该如何避免在搜索中选到那些正在传输的文件呢?

提前感谢你们提供的任何帮助。

3 个回答

0

你可以尝试在移动文件之前对它进行独占写入锁定。这可以通过使用 fcntl 模块来实现:

http://docs.python.org/library/fcntl.html

如果不想用这个方法,你可以使用 lsof 工具来查看系统中哪些文件是打开的。不过,这样会需要更多的麻烦。

需要注意的是,os.rename() 在同一个文件系统上是可以正常工作的,而且不会受到这个问题的影响(因为只是移动了 inode,而没有移动数据)。而使用 shutil 的话,就像 mv 命令一样,如果是在同一个文件系统上,它会重新链接文件;如果是在不同的文件系统上,则会先复制文件再删除原文件。

0

Mac电脑里的 ._ 文件包含了一些资源信息。想了解更多,可以查看这里:http://support.apple.com/kb/TA20578

因为我没有足够的权限来评论,所以我在这里直接回答。

大多数情况下,你可以放心地忽略这些文件,因为其他操作系统可能根本无法处理它们。想了解更多信息,可以查看这里:http://en.wikipedia.org/wiki/Resource_fork

0

结果发现,写锁的方法并没有奏效。我想我在更新之前没有好好测试过。

我现在决定做的是:

  • 把检查之间的时间缩短到30秒
  • 保留上一次找到的文件列表和它们各自的文件大小
  • 把新文件列表和旧文件列表进行对比

如果新列表里有和旧列表里相同的文件,并且文件大小也一样,就把它放到一个待转移的列表里。新列表里剩下的文件就变成旧列表,然后继续这个过程。

我相信lsof这个方法是可行的,但我不太确定怎么在python里使用它。而且这个方法应该很适合我的情况,因为我主要是担心在文件转移时不想移动它们。

我还需要排除所有以“._”开头的文件,因为这些是mac生成的,我不确定它们的大小是否会随着时间增加。

另外,我可以选择只处理那些由她的mac在转移的情况。我知道当mac在转移文件时,会生成:

  • filename.ext
  • ._filename.ext

我可以检查列表,找出所有以“._”开头的filename,并把这些文件排除掉。

我可能会先试试第二个选项。虽然这个方法有点不太干净,但希望能奏效。

撰写回答