使用PHP文件锁写一个多个请求同时并发写入一个文件,要求不脏读、数据不丢失.
//并发文件操作 function filehandle($filename,$data){ $start = 0; $end = 3000; if(!file_exists($filename)){ return "文件不存在"; } if(!is_string($data)){ return "写入内容只能为字符串类型"; } if($fp = fopen($filename,'a')){ do{ //获取文件独占锁 $canWrite = flock($fp,LOCK_EX); if(!$canWrite){ $rand = mt_rand(1,100); //让程序休眠随机毫秒数再试 usleep($rand*1000); $start += $rand; } }while(!$canWrite && $start < $end); if(!$canWrite){ //未能获得锁 return "获取文件锁失败"; }else{ fwrite($fp,$data); } //释放锁定,关闭文件 flock($fp, LOCK_UN); fclose($fp); return true; }else{ return "打开文件失败"; } }
此方法的要点是当用户操作文件的时候必须获取文件的独占锁,若文件已经被锁定,则让程序休眠若干毫秒后重试,知道获得锁或者超时为止。
flock():轻便的咨询文件锁定
函数参数说明:
handle - 文件系统指针,是典型地由 fopen() 创建的 resource(资源)。
operation - 可以是以下值之一:
LOCK_SH
取得共享锁定(读取的程序)。LOCK_EX
取得独占锁定(写入的程序。LOCK_UN
释放锁定(无论共享或独占)。
返回值:成功时返回 TRUE
, 或者在失败时返回 FALSE
。
方案二:
file_put_contents($filename, $data, FILE_APPEND|LOCK_EX);
int file_put_contents ( string $filename , mixed $data [, int $flags = 0 [, resource $context ]] );
函数说明:将一个字符串写入文件
参数说明:
filename - 要被写入数据的文件名。
data - 要写入的数据。类型可以是 string,array(一维) 或者是 stream 资源。
flags - flags的值可以是 以下 flag 使用 OR (|) 运算符进行的组合。
FILE_USE_INCLUDE_PATH : 在 include 目录里搜索 filename。 更多信息可参见 include_path。
FILE_APPEND : 如果文件 filename 已经存在,追加数据而不是覆盖。
LOCK_EX : 在写入时获得一个独占锁。
context - 一个 context 资源。
返回值:该函数将返回写入到文件内数据的字节数,失败时返回FALSE
(注:以上方案均未经过实际项目测试)