如何在Perl中锁定文件?

时间:2020-03-05 18:45:07  来源:igfitidea点击:

在Perl中为文件创建锁的最佳方法是什么?

最好聚集在文件上或者创建一个锁定文件以放置一个锁定并检查该锁定文件上的锁定吗?

解决方案

回答

使用羊群卢克。

编辑:这是一个很好的解释。

回答

flock创建Unix风格的文件锁,并且可在大多数OS的Perl上运行。但是,羊群的锁仅供参考。

编辑:强调羊群是可移植的

回答

如果最终使用了flock,请执行以下代码:

use Fcntl ':flock'; # Import LOCK_* constants

# We will use this file path in error messages and function calls.
# Don't type it out more than once in your code.  Use a variable.
my $file = '/path/to/some/file';

# Open the file for appending.  Note the file path is quoted
# in the error message.  This helps debug situations where you
# have a stray space at the start or end of the path.
open(my $fh, '>>', $file) or die "Could not open '$file' - $!";

# Get exclusive lock (will block until it does)
flock($fh, LOCK_EX) or die "Could not lock '$file' - $!";

# Do something with the file here...

# Do NOT use flock() to unlock the file if you wrote to the
# file in the "do something" section above.  This could create
# a race condition.  The close() call below will unlock the
# file for you, but only after writing any buffered data.

# In a world of buffered i/o, some or all of your data may not 
# be written until close() completes.  Always, always, ALWAYS 
# check the return value of close() if you wrote to the file!
close($fh) or die "Could not write '$file' - $!";

一些有用的链接:

  • PerlMonks文件锁定教程(有些旧)
  • flock()文档

为了回答我们添加的问题,我想说是在文件被锁定时将其置于文件上或者创建一个称为"锁定"的文件,然后在不再锁定时将其删除(然后确保程序遵循这些语义)。

回答

通过CPAN进行救援:IO :: LockedFile。

回答

我在这个问题上的目标是锁定一个文件,该文件用作多个脚本的数据存储。最后,我使用了与以下类似的代码(来自Chris):

open (FILE, '>>', test.dat') ; # open the file 
flock FILE, 2; # try to lock the file 
# do something with the file here 
close(FILE); # close the file

在他的示例中,我删除了群文件FILE,因为close(FILE)也执行此操作。真正的问题是,脚本启动时必须保留当前计数器,脚本结束时必须更新计数器。这是Perl遇到的问题,要读取文件:

open (FILE, '<', test.dat');
 flock FILE, 2;

现在,我想写出结果,并且由于我想覆盖文件,因此我需要重新打开并截断其结果,结果如下:

open (FILE, '>', test.dat'); #single arrow truncates double appends
 flock FILE, 2;

在这种情况下,实际上在重新打开文件时,文件会在短时间内解锁。这说明了外部锁定文件的情况。如果要更改文件的上下文,请使用锁定文件。修改后的代码:

open (LOCK_FILE, '<', test.dat.lock') or die "Could not obtain lock";
flock LOCK_FILE, 2;
open (FILE, '<', test.dat') or die "Could not open file";
# read file
# ...
open (FILE, '>', test.dat') or die "Could not reopen file";
#write file
close (FILE);
close (LOCK_FILE);

回答

我们是否考虑过使用LockFile :: Simple模块?它已经为我们完成了大部分工作。

根据我过去的经验,我发现它非常易于使用和坚固。

回答

我认为将词汇变量作为文件处理程序来显示会更好
和错误处理。
使用Fcntl模块中的常量也比硬编码魔术数字2更好,因为魔术数字2可能不是在所有操作系统上都正确的数字。

use Fcntl ':flock'; # import LOCK_* constants

    # open the file for appending
    open (my $fh, '>>', 'test.dat') or die $!;

    # try to lock the file exclusively, will wait till you get the lock
    flock($fh, LOCK_EX);

    # do something with the file here (print to it in our case)

    # actually you should not unlock the file
    # close the file will unlock it
    close($fh) or warn "Could not close file $!";

查阅flock的完整文档和PerlMonks上的File Locking教程,尽管这也使用了旧式的文件句柄用法。

实际上,我通常跳过close()上的错误处理,因为没有
如果仍然失败,我可以做很多事情。

关于锁定什么,如果我们在单个文件中工作,则锁定该文件。如果我们需要一次锁定多个文件,则为了避免死锁,最好选择一个要锁定的文件。不管这是我们真正需要锁定的几个文件之一,还是仅出于锁定目的而创建的单独文件,都没有关系。

回答

Ryan P写道:

In this case the file is actually unlocked for a short period of time while the file is reopened.

所以不要那样做。相反,请打开文件以进行读取/写入:

open my $fh, '+<', 'test.dat'
    or die "Couldn’t open test.dat: $!\n";

准备好编写计数器时,只需"搜索"回到文件的开头。请注意,如果这样做,则应在close之前truncate,这样,如果文件的新内容比以前的内容短,就不会留下尾随垃圾。 (通常,文件中的当前位置在文件的末尾,因此我们可以只写truncate $ fh,告诉$ fh。)

另外,请注意,我使用了三个参数的" open"和一个词汇文件句柄,并且我还检查了操作是否成功。请避免使用全局文件句柄(全局变量不好,mmkay?)和不可思议的两个参数" open"(这是Perl代码中许多(无法利用的)错误的源头),并始终测试" open"是否正确成功。

回答

use strict;

use Fcntl ':flock'; # Import LOCK_* constants

# We will use this file path in error messages and function calls.
# Don't type it out more than once in your code.  Use a variable.
my $file = '/path/to/some/file';

# Open the file for appending.  Note the file path is in quoted
# in the error message.  This helps debug situations where you
# have a stray space at the start or end of the path.
open(my $fh, '>>', $file) or die "Could not open '$file' - $!";

# Get exclusive lock (will block until it does)
flock($fh, LOCK_EX);

# Do something with the file here...

# Do NOT use flock() to unlock the file if you wrote to the
# file in the "do something" section above.  This could create
# a race condition.  The close() call below will unlock it
# for you, but only after writing any buffered data.

# In a world of buffered i/o, some or all of your data will not 
# be written until close() completes.  Always, always, ALWAYS 
# check the return value on close()!
close($fh) or die "Could not write '$file' - $!";

回答

这是我一锁读写的解决方案...

open (TST,"+< readwrite_test.txt") or die "Cannot open file\n$!";
flock(TST, LOCK_EX);
# Read the file:
@LINES=<TST>;
# Wipe the file:
seek(TST, 0, 0); truncate(TST, 0);
# Do something with the contents here:
push @LINES,"grappig, he!\n";
$LINES[3]="Gekke henkie!\n";
# Write the file:
foreach $l (@LINES)
{
   print TST $l;
}
close(TST) or die "Cannot close file\n$!";