搜索文件中的内容并使用PHP更改内容的最佳(最有效)方法是什么?

Don*_*mmy 5 php io file

我有一个用PHP阅读的文件.我想寻找一些以一些空格开头的行,然后是我正在寻找的一些关键词(例如,"project_name:"),然后更改该行的其他部分.

目前,我处理这个问题的方法是将整个文件读入一个字符串变量,操作该字符串,然后将整个文件写回文件,完全替换整个文件(通过fopen( filepath, "wb" )fwrite()),但这感觉效率低下.有没有更好的办法?

hek*_*mgl 3

更新:完成我的函数后,我有时间对其进行基准测试。我使用了一个1GB大文件进行测试,但结果并不令人满意:|

是的,内存峰值分配明显更小:

  • 标准解决方案:1.86 GB
  • 自定义解决方案:653 KB(4096 字节缓冲区大小)

但与以下解决方案相比,性能仅略有提升:

ini_set('memory_limit', -1);

file_put_contents(
    'test.txt',
    str_replace('the', 'teh', file_get_contents('test.txt'))
);
Run Code Online (Sandbox Code Playgroud)

上面的脚本花费了约 16 秒,自定义解决方案花费了约 13 秒。

恢复:客户解决方案在处理大文件时速度稍快,并且消耗的内存少得多(!!!)。

此外,如果您想在 Web 服务器环境中运行它,则自定义解决方案会更好,因为许多并发脚本可能会消耗系统的整个可用内存。


原答案:

唯一想到的就是以适合文件系统块大小的块读取文件,并将内容或修改的内容写回临时文件。处理完成后,您可以使用rename()覆盖原始文件。

这将减少内存峰值,并且如果文件确实很大的话,速度应该会明显加快。

注意:在 Linux 系统上,您可以使用以下命令获取文件系统块大小:

sudo dumpe2fs /dev/yourdev | grep 'Block size'
Run Code Online (Sandbox Code Playgroud)

我有4096

函数来了:

function freplace($search, $replace, $filename, $buffersize = 4096) {

    $fd1 = fopen($filename, 'r');
    if(!is_resource($fd1)) {
        die('error opening file');
    }   

    // the tempfile can be anywhere but on the same partition as the original
    $tmpfile = tempnam('.', uniqid());
    $fd2 = fopen($tmpfile, 'w+');

    // we store len(search) -1 chars from the end of the buffer on each loop
    // this is the maximum chars of the search string that can be on the 
    // border between two buffers
    $tmp = ''; 
    while(!feof($fd1)) {
        $buffer = fread($fd1, $buffersize);
        // prepend the rest from last one
        $buffer = $tmp . $buffer;
        // replace
        $buffer = str_replace($search, $replace, $buffer);
        // store len(search) - 1 chars from the end of the buffer
        $tmp = substr($buffer, -1 * (strlen($search)) + 1); 
        // write processed buffer (minus rest)
        fwrite($fd2, $buffer, strlen($buffer) - strlen($tmp));
    };  

    if(!empty($tmp)) {
        fwrite($fd2, $tmp);
    }   

    fclose($fd1);   
    fclose($fd2);
    rename($tmpfile, $filename);
}
Run Code Online (Sandbox Code Playgroud)

像这样称呼它:

freplace('foo', 'bar', 'test.txt');
Run Code Online (Sandbox Code Playgroud)

  • 如果搜索字符串跨越读取缓冲区会发生什么? (2认同)