在php中读取和覆盖文件内容的最佳方法是什么?

时间:2011-08-19 19:30:51

标签: php file fopen fwrite fread

在php中打开文件,读取内容,然后使用基于原始内容的一些输出覆盖文件内容的最简洁方法是什么?具体来说,我正在尝试打开一个填充了项目列表的文件(由换行符分隔),处理/添加项目到列表,从列表中删除最旧的N个条目,最后将列表写回文件。 / p>

fopen(<path>, 'a+')
flock(<handle>, LOCK_EX)
fread(<handle>, filesize(<path>))
// process contents and remove old entries
fwrite(<handle>, <contents>)
flock(<handle>, LOCK_UN)
fclose(<handle>)

请注意,我需要使用flock()锁定文件,以便在多个页面请求中保护它。当fopen()进行诀窍时,'w +'会标记吗? php手册指出它会将文件截断为零长度,因此似乎可能会阻止我读取文件的当前内容。

3 个答案:

答案 0 :(得分:1)

如果文件不是太大(也就是说,你可以放心加载它不会破坏PHP的内存限制),那么最简单的方法就是将整个文件读成一个字符串({{1处理字符串,并将结果写回文件(file_get_contents())。这种方法有两个问题:

  • 如果文件太大(比如几十或几百兆字节),或者处理内存不足,你就会耗尽内存(当你运行多个实例时更是如此)
  • 手术具有破坏性;当保存在中途失败时,您将丢失所有原始数据。

如果其中任何一个是问题,计划B是处理文件,同时写入临时文件;成功完成后,关闭两个文件,重命名(或删除)原始文件,然后将临时文件重命名为原始文件名。

答案 1 :(得分:0)

$data = file_get_contents($filename);

file_put_contents($filename, $data);

答案 2 :(得分:0)

一种解决方案是使用单独的锁定文件来控制访问。

此解决方案假定只有您的脚本或您有权访问的脚本要写入文件。这是因为脚本需要知道检查单独的文件以进行访问。

$file_lock = obtain_file_lock();
if ($file_lock) {
    $old_information = file_get_contents('/path/to/main/file');
    $new_information = update_information_somehow($old_information);
    file_put_contents('/path/to/main/file', $new_information);
    release_file_lock($file_lock);
}

function obtain_file_lock() {

    $attempts = 10;
    // There are probably better ways of dealing with waiting for a file
    // lock but this shows the principle of dealing with the original 
    // question.

    for ($ii = 0; $ii < $attempts; $ii++) {
         $lock_file = fopen('/path/to/lock/file', 'r'); //only need read access
         if (flock($lock_file, LOCK_EX)) {
             return $lock_file;
         } else {
             //give time for other process to release lock
             usleep(100000); //0.1 seconds
         }
    }
    //This is only reached if all attempts fail.
    //Error code here for dealing with that eventuality.
}

function release_file_lock($lock_file) {
    flock($lock_file, LOCK_UN);
    fclose($lock_file);
}

这应该防止同时运行的脚本读取旧信息并进行更新,从而导致您在读取文件后丢失其他脚本已更新的信息。它将仅允许脚本的一个实例读取文件,然后使用更新的信息覆盖文件。

尽管这有望回答原始问题,但不能确保所有并发脚本最终具有记录其信息的能力。