2011-04-15 104 views
4

我需要锁定文件,读取数据,写入文件然后关闭它。我有的问题是我试图找到fopen的正确模式。Fopen,fread和羊群

'a +' - 总是追加数据,'w +'在打开时截断所有数据,'x +'无法锁定文件。

这是我的代码:

$fh_task = fopen($task_file, 'w+'); 
flock($fh_task, LOCK_EX) or die('Cant lock '.$task_file); 
$opt_line = ''; 
while(!feof($fh_task)){ 
    $opt_line .= fread($fh_task, 4096); 
} 
$options = unserialize($opt_line); 
$options['procceed']++; 
rewind($fh_task); 
fwrite($fh_task, serialize($options)); 
flock($fh_task, LOCK_UN); 
fclose($fh_task); 
+1

alexy13,感谢编辑,我的英语很糟糕-____- – Kein 2011-04-15 22:12:32

回答

7

你想'r+'(或c+如果你使用PHP的新版本)。 r+不会截断(c+也不会截断),但仍允许您编写。

这里是从我上次具有这些功能的工作的摘录:

 /* 
      if file exists, open in read+ plus mode so we can try to lock it 
      -- opening in w+ would truncate the file *before* we could get a lock! 
     */ 

     if(version_compare(PHP_VERSION, '5.2.6') >= 0) { 
      $mode = 'c+'; 
     } else { 
      //'c+' would be the ideal $mode to use, but that's only 
      //available in PHP >=5.2.6 

      $mode = file_exists($file) ? 'r+' : 'w+'; 
      //there's a small chance of a race condition here 
      // -- two processes could end up opening the file with 'w+' 
     } 

     //open file 
     if($handle = @fopen($file, $mode)) { 
      //get write lock 
      flock($handle,LOCK_EX); 
      //write data 
      fwrite($handle, $myData); 
      //truncate all data in file following the data we just wrote 
      ftruncate($handle,ftell($handle)); 
      //release write lock -- fclose does this automatically 
      //but only in PHP <= 5.3.2 
      flock($handle,LOCK_UN); 
      //close file 
      fclose($handle); 
     } 
+0

'羊群($处理,LOCK_UN)'不是必需的,因为'FCLOSE($处理)'这是否反正 - 至少perl文档陈述如此。 – drahnr 2012-08-15 15:30:13

+2

看起来像最近在PHP中可能已经发生了变化。 '在5.3.2之前的PHP版本中,锁也是通过fclose()释放的(当脚本完成时它也被自动调用)。http://php.net/flock当文件的资源句柄是自动解锁关闭[5.3.2]被删除。现在解锁总是必须手动完成。“ – 2012-08-16 00:22:44

+0

我的错,missread php as perl。 – drahnr 2012-08-16 00:32:06

2

我相信你想c+。这与r+类似,只是它会创建一个不存在的文件。如果您不想这样做,请改为使用r+。打开文件后,根据需要使用flock()。你也可以打开c+阅读和写作。除此之外,我认为你可以使用相同的代码。

其他答案是正确的,但他们正在使用额外的步骤来确定使用r或w时,c会自动执行此操作。

+0

+1。编辑我的答案并入'C +',因为它绝对是解决问题的正确方案。编辑:哦。 'c +'只能从5.2.6开始 – 2012-08-16 00:28:31

0

Frank Farmer的代码并不比你的更好。在file_exists和fopen之间的其他进程可以用文件做他自己的操作。

打开“任务”文件前创建信号量文件。
喜欢的东西:

if (($f_sem = @fopen($task_file.'.sem', 'x'))) 
{ 
    //your code (with flock) 
    fclose($f_sem); 
    unlink($task_file.'.sem'); 
} 
+0

我认为这不是个好主意。任务文件这是在线程下进行通信的方式。当我使用简单的锁,每个线程等待,直到文件锁定释放。有了信号量文件,我只是为了创建它而没有更多。 – Kein 2011-04-16 04:08:29

+0

如果你真的想创建等待解锁(这种方式可能是危险的),比应用群集到信号量文件,这很容易 - 在我的代码在你的代码之前写入群集。 – 2011-04-16 09:54:23