检测到文件正在被复制到文件夹中

Posted

技术标签:

【中文标题】检测到文件正在被复制到文件夹中【英文标题】:Detecting that files are being copied in a folder 【发布时间】:2017-02-22 14:02:56 【问题描述】:

我正在运行一个脚本,如果该文件夹不存在(或不一致),它会从特定位置复制一个文件夹。当我同时运行脚本 2 次以上时,就会出现问题。当第一个脚本试图复制文件时,第二个脚本来尝试同样的事情,导致一团糟。我怎样才能避免这种情况?类似于系统范围的互斥锁。

我用-w 尝试了一个简单的测试,我手动复制了文件夹,在复制文件夹时我运行了脚本:

use strict;
use warnings;

my $filename = 'd:\\folder_to_copy';
if (-w $filename) 
  print "i can write to the file\n";
 else 
  print "yikes, i can't write to the file!\n";

这当然行不通,因为我仍有对该文件夹的写入权限。 关于如何检查该文件夹是否被复制到Perl 或使用batch commands 的任何想法?

【问题讨论】:

【参考方案1】:

听起来像是lock file 的工作。有无数的 CPAN 模块实现了锁定文件,但大多数都不能在 Windows 上运行。根据 CPAN 测试人员的说法,这里有一些似乎支持 Windows:

File::Lockfile File::TinyLock File::Flock::Tiny

快速查看源代码后,我唯一推荐的模块是File::Flock::Tiny。其他人看起来很活泼。

【讨论】:

所以为了知道我仍在该文件夹中复制,我会锁定特定文件,直到我完成整个文件夹的复制并且检查该文件? @JohnDoe 是的,您必须使用单独的文件作为锁定文件。【参考方案2】:

如果您需要一个系统范围的互斥锁,那么一个“技巧”就是(ab)使用一个目录。命令mkdir 通常是原子的,要么有效要么无效(如果目录已经存在)。

如下更改你的脚本:

my $mutex_dir = '/tmp/my-mutex-dir';
if ( mkdir $mutex_dir ) 

    # run your copy-code here

    # when finished:
    rmdir $mutex_dir;
 else 
    print "another instance is already running.\n";

您唯一需要确保的是允许您在/tmp(或任何地方)中创建目录。

请注意,我故意首先测试$mutex_dir 的存在,因为在if (not -d $mutex_dir)mkdir 之间,其他人可以创建目录,而mkdir 无论如何都会失败.所以只需致电mkdir。如果它有效,那么你可以做你的事情。完成后不要忘记删除$mutex_dir

这也是这种方法的缺点:如果您的复制代码崩溃并且脚本过早死亡,那么该目录不会被删除。大概nwellnhof's answer 中建议的锁定文件机制在这种情况下表现得更好,并自动解锁文件。

【讨论】:

有没有可能失败的情况?有什么特殊情况吗? 整个事情取决于mkdir的原子性。在 Unix 下,该操作是原子的。在 Windows 下,我不太确定,谷歌在这里不再提供帮助。我找到了这两种说法。 如果mkdir在Windows下是原子的,那么我不知道这种方法会失败的情况(除了缺少权限)。【参考方案3】:

当第一个脚本试图复制文件时,第二个脚本来了 尝试同样的事情导致一团糟

如果另一个脚本实例正在运行,最简单的方法是创建一个包含 1 的文件。然后你可以在此基础上添加一个条件。

local $/; open my $fh, "<", 'flag' or die $!; $data = <$fh>;
die "another instance of script is running" if $data == 1;

另一种方法是在脚本中设置一个环境变量并在BEGIN 块中检查它。

【讨论】:

这很容易出现竞争条件。 谢谢你的回答,它真的很聪明,但我可以将问题从文件夹中移出,正如@nwellnhof 所说,在包含标志的文件中。【参考方案4】:

您可以使用包的 Windows-Mutex 或 Windows-Semaphore 对象 http://search.cpan.org/~cjm/Win32-IPC-1.11/

use Win32::Mutex;
use Digest::MD5 qw (md5_hex);
my $mutex = Win32::Mutex->new(0, md5_hex $filename);
if ($mutex) 
     do_your_job();
     $mutex->release
 else 
     #fail...

【讨论】:

这也是一种有趣的方法,但我想坚持使用默认提供的模块。

以上是关于检测到文件正在被复制到文件夹中的主要内容,如果未能解决你的问题,请参考以下文章

inotify IN_CLOSE_WRITE 仅检测复制到目录的文件

如何获取文本文件的内容并将其复制到剪贴板?

检测文件何时被拖到文件输入

拖动到浏览器并检测被删除的文件的 mime

子目录中的资源文件被复制到 app bundle 的根目录

检测传输中的文件?