2

如果您确实使用了简单的 fopen/fwrite(),例如:

$ref = @fopen('/path/to/file', 'x+b'); // returns false if already exists
if ($ref) {
    fwrite($ref, 'A');
    sleep(5);
    fwrite($ref, 'B');
}

如果其他进程在睡眠期间删除了文件,如何检查文件指针是否仍然有效?

我考虑过使用简单的 is_file() 检查,但这并不能说明另一个进程是否执行了 unlink() 然后创建了一个具有相同路径的新文件。

作为参考,即使文件已取消链接(),fwrite 似乎仍然返回 true。

编辑:澄清一下,sleep(5) 只是一个随机时间,在竞争条件下可能只是几毫秒。

4

4 回答 4

4

我刚刚做了一个测试,似乎这fstat是解决方案:

$fd = fopen("/path/to/file", "w");
var_dump(fstat($fd)); // shows ['nlink'] => int(1)
sleep(60);
// in a shell console, remove the file
var_dump(fstat($fd)); // shows ['nlink'] => int(0)
于 2012-11-19T09:51:43.073 回答
2

您需要再次执行 fopen()。在 linux 系统上,您可以写入已删除的文件,因为您仍然引用它。当您关闭它时,该文件将最终被删除。

如果进程需要等待我会关闭,然后在睡眠之间打开文件

于 2012-11-19T09:12:45.837 回答
2

如果您持有文件的句柄,则无需打扰。文件系统正在处理这个问题。

编辑

句柄是有效的,除非您关闭它或脚本结束并且删除文件与句柄的有效性绝对无关,锁定也是如此。通过创建大文件(1GB)并开始使用浏览器获取即可以轻松地检查这一点,您现在可以“安全地”从其他进程中删除它。这不会影响获取甚至ls不再将文件列为现有的工具。我写了“安全”,因为如果下载失败,那么 httpd 将关闭打开的句柄,然后,如果没有其他进程持有句柄,它将 phisicaly 释放磁盘空间。但只要至少有一个引用它,数据就会保留在磁盘上(可以通过使用以下工具检查可用磁盘空间来轻松检查df- 按顺序:

create 1GB file
df
start download
rm file
df

第二个df将表明磁盘空间与第一个相同(当然假设没有发生其他文件操作)。现在停止下载并df重新下载。可用空间现在增加了 1GB。

请注意,Windows 的 FS 不会让您删除打开的文件,但这只是实施问题,而不是技术限制。*nix 上的大多数(如果不是每个)FS 都可以毫无问题地处理这个问题。

于 2012-11-19T09:12:57.313 回答
0

只是为了增加很多精度: fopen() 锁定取决于您打开文件的类型。w并且w+会锁定 - r, a,r+不会(默认情况下)。但是,如果您真的想确保您的文件不能在其他地方使用,该功能flock()可能会派上用场。

但是,如果您真的需要锁定文件并且在 5 秒内什么都不做,我会质疑您的设计/实现,而不是找到解决方法。

于 2012-11-19T09:16:29.047 回答