2011-04-15 86 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