更新:完成我的功能后,我有时间对其进行基准测试。我使用了一个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'))
);
上面的脚本需要大约16秒,而自定义解决方案只需要大约13秒。
总结:自定义解决方案对于大文件来说稍微更快,并且消耗的内存要少得多(!!!)。
此外,如果您想在Web服务器环境中运行此操作,则自定义解决方案更好,因为许多并发脚本可能会消耗系统中所有可用的内存。
原始答案:
我能想到的唯一方法是按适合文件系统块大小的块读取文件,并将内容或修改后的内容写回临时文件。处理完成后,使用rename()
覆盖原始文件。
这将减少内存峰值,并且如果文件确实很大,则应显着加快速度。
注意:在Linux系统上,您可以使用以下命令获取文件系统块大小:
sudo dumpe2fs /dev/yourdev | grep 'Block size'
我得到了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);
}
像这样调用它:
freplace('foo', 'bar', 'test.txt');