file_put_contents 在另一个进程正在写入的文件上追加数据

file_put_contents appending data on a file being written by another process

我有

$bytesCount = file_put_contents( "somefile.log", "some text\n", FILE_APPEND | LOCK_EX );

如果另一个进程正在 somefile.log 上写入**会怎样?

file_put_contents 是否因运行时错误而失败?

如果 $bytesCount === false

失败则执行

还是暂停脚本直到文件解锁,然后执行写入操作?


(**) 或更一般地,另一个进程对该文件具有独占锁


[ 我在 *nix 平台上 php 5.6 ]

很明显,这应该只在你写一次时使用,如果你多次写同一个文件,你应该用 fopen 和 fwrite 自己处理,写完后的 fclose .

基准如下:

file_put_contents() 1,000,000 次写入 - 3 个基准的平均值:

实际 0m3.932s 用户 0m2.487s 系统 0m1.437s

fopen() fwrite() 1,000,000 次写入,fclose() - 3 个基准的平均值:

实际 0m2.265s 用户 0m1.819s 系统 0m0.445s

对于使用 ftp 时的覆盖,这很有帮助:

/* create a stream context telling PHP to overwrite the file */ 
$options = array('ftp' => array('overwrite' => true)); 
$stream = stream_context_create($options);

http://php.net/manual/en/function.file-put-contents.php

file_put_contents 尝试写入锁定的文件时 等待文件解锁然后执行写入 和 returns 写入的字节数。


证明:

我写了一个简单的双脚本测试:

第一个脚本写入一个 100MB 的文件(在连接 USB2 的慢速驱动器上);

第二个脚本将一个短字符串附加到同一个文件。

两个脚本的核心就是这四行:

echo Milliseconds() . ": Start writing file on file\n";
$bytesCount = file_put_contents( "/Volumes/myHD/somefile.txt", $buffer, FILE_APPEND | LOCK_EX );
var_export( $bytesCount );
echo "\n" . Milliseconds() . ": Done writing on file\n";

其中 Milliseconds() 是 returns 当前 unix 时间戳(以毫秒为单位)的函数。

在第一个脚本中 $buffer 是一个 100MB 的字符串,在第二个脚本中 $buffer = "MORE-DATA\n";

运行 第一个脚本并快速启动第二个脚本导致此输出:

脚本 1:

$ php test1.php
1481892766645: Start writing file on file
100000000
1481892769680: Done writing on file
$

脚本 2:

$ php test2.php
1481892766831: Start writing file on locked file
10
1481892769909: Done writing file on locked file
$

注意:

  • 第二个脚本在第一个脚本之后 186 毫秒尝试写入,但在第二个脚本完成写入之前。所以第二个脚本实际上访问了一个锁定的文件。

  • 第二个脚本在第一个脚本后 229 毫秒终止写入

检查两个脚本终止执行后的结果:

$ stat -f%z /Volumes/myHD/somefile.txt 
100000010
$

已写入 10MB + 10 个字节

$ tail -c 20 /Volumes/myHD/somefile.txt
0123456789MORE-DATA 
$

第二个脚本实际上是在文件末尾追加了字符串