如何避免通过单独的脚本实例获取同一文件的内容


How to avoid getting contents of the same file by separate script instances?

假设我们有:文件:a.txt、b.txt和c.txtscript:script.php

我们希望允许脚本获取文件的名称(其中任何一个)、内容,然后将其删除,这样单独运行的同一脚本就不能获得同一文件。

到目前为止:

$scan = scandir('dir');
unset($scan[0], $scan[1]);
shuffle($scan);
$file = $scan[0];
$contents = file_get_contents($file);
if(unlink($file) !== false)
return $contents;

使用类似flock的文件锁定。

我认为算法是:

  1. 打开文件
  2. flock取锁
  3. 检查文件是否仍然存在。如果它已经消失,转到7
  4. 读取文件
  5. 删除它
  6. 解锁它
  7. 关闭文件,忽略失败

步骤3是必需的,因为任何等待从另一个进程获取锁的进程都必然会丢失文件,因为在获取锁时该文件已被删除。

我认为在文件打开时删除它是非常安全的;只有后续的文件操作才会失败。删除被锁定的文件并没有错,因为锁与文件并没有真正的强关联,它们只是作为文件描述符表进行维护。

我认为您应该在最后关闭文件,即使它已经被删除,因为可能有操作系统资源需要清理。我不确定关闭是否会失败,但您可以简单地忽略失败(大多数人都会忽略close()的返回值)。

另一种不必删除文件的方法是维护一个包含所有文件(文件名、读取状态)的数据库表。最初,它们都将readstatus设置为0。然后,php脚本可以从表中获取文件名,并将readstatus设置为1,这样脚本的另一个实例就不会再次获取相同的文件名。

这也会处理冲突,因为数据库会自动实现行级或表级锁定,确保脚本的两个实例不会接收到相同的文件名。