用PHP替换大文件中的字符串

时间:2010-01-29 00:25:04

标签: php string replace readfile

我正在尝试用PHP替换整个文件的字符串。我的文件超过100MB所以我必须逐行,不能使用file_get_contents()。对此有一个很好的解决方案吗?

6 个答案:

答案 0 :(得分:11)

如果您不需要使用PHP,我强烈建议您从命令行执行此类操作。它是最好的工具,更容易使用。

在任何情况下,sed (Stream Editor)命令都是您要找的:

sed s/search/replace oldfilename > newfilename

如果您需要不区分大小写:

sed -i s/search/replace oldfilename > newfilename

如果您需要在PHP中动态执行此操作,可以使用passthru()

$output = passthru("sed s/$search/$replace $oldfilename > $newfilename");

答案 1 :(得分:6)

你走了:

function replace_file($path, $string, $replace)
{
    set_time_limit(0);

    if (is_file($path) === true)
    {
        $file = fopen($path, 'r');
        $temp = tempnam('./', 'tmp');

        if (is_resource($file) === true)
        {
            while (feof($file) === false)
            {
                file_put_contents($temp, str_replace($string, $replace, fgets($file)), FILE_APPEND);
            }

            fclose($file);
        }

        unlink($path);
    }

    return rename($temp, $path);
}

这样称呼:

replace_file('/path/to/fruits.txt', 'apples', 'oranges');

答案 2 :(得分:3)

如果你不能直接从命令行使用sed,因为它是一个动态任务,你需要从php调用它很难得到正确的语法:你必须在搜索和替换字符串中以不同的方式转义这些字符< / p>

' / $ . * [ ] \ ^ &

以下函数搜索并替换文件中的字符串,而将搜索到的字符串解释为正则表达式。因此,如果您想要,可以搜索字符串“。*”并将其替换为“$”。

/**
 * str_replace_with_sed($search, $replace, $file_in, $file_out=null)
 * 
 * Search for the fixed string `$search` inside the file `$file_in`
 * and replace it with `$replace`. The replace occurs in-place unless
 * `$file_out` is defined: in that case the resulting file is written
 * into `$file_out`
 *
 * Return: sed return status (0 means success, any other integer failure)
 */
function str_replace_with_sed($search, $replace, $file_in, $file_out=null)
{
    $cmd_opts = '';
    if (! $file_out) 
    {
        // replace inline in $file_in
        $cmd_opts .= ' -i';
    }

    // We will use Basic Regular Expressions (BRE). This means that in the 
    // search pattern we must escape
    // $.*[\]^
    //
    // The replacement string must have these characters escaped
    // \ & 
    //
    // In both cases we must escape the separator character too ( usually / )
    // 
    // Since we run the command trough the shell we We must escape the string
    // too (yai!). We're delimiting the string with single quotes (') and we'll
    // escape them with '\'' (close string, write a single quote, reopen string)    

    // Replace all the backslashes as first thing. If we do it in the following
    // batch replace we would end up with bogus results
    $search_pattern = str_replace('\\', '\\\\', $search);

    $search_pattern = str_replace(array('$', '.', '*', '[', ']', '^'),
                                  array('\\$', '\\.', '\\*', '\\[', '\\]', '\\^'),
                                  $search_pattern);

    $replace_string = str_replace(array('\\', '&'),
                                  array('\\\\', '\\&'),
                                  $replace);

    $output_suffix = $file_out ? " > '$file_out' " : '';
    $cmd = sprintf("sed ".$cmd_opts." -e 's/%s/%s/g' \"%s\" ".$output_suffix,
                    str_replace('/','\\/', # escape the regexp separator
                      str_replace("'", "'\''", $search_pattern) // sh string escape
                    ),
                    str_replace('/','\\/', # escape the regexp separator
                      str_replace("'", "'\''", $replace_string) // sh string escape
                    ),
                    $file_in
                  );

    passthru($cmd, $status);

    return $status;
}

答案 3 :(得分:1)

一次获取几行,转储变量,获取接下来的几行。

$fh = fopen("bigfile.txt", "flags");
$num = 0;
$length = 300;
$filesize = filesize("bigfile.txt");

while($num < $filesize)
{
     $contents = fread($fh, $length);
     // .. do stuff ...
     $num = $num+$length;
     fseek($fh, $num);
}

fclose($fh);

您将要确保这是正确的(尚未测试)。查看PHP Documentation.

上的图书馆

棘手的部分是写回文件。弹出我脑海中的第一个想法是进行字符串替换,将新内容写入另一个文件,然后最后删除旧文件并将其替换为新文件。

答案 4 :(得分:1)

这样的事情?

$infile="file";
$outfile="temp";
$f = fopen($infile,"r");
$o = fopen($outfile,"a");
$pattern="pattern";
$replace="replace";
if($f){
     while( !feof($f) ){
        $line = fgets($f,4096);
        if ( strpos($pattern,"$line") !==FALSE ){
            $line=str_replace($pattern,$replace,$line);
        }
        fwrite($o,$line);
     }
}
fclose($f);
fclose($o);
rename($outfile,$infile);

答案 5 :(得分:1)

我会使用&#39; sed&#39;以更明确的方式,因此您不太依赖于您的系统。

$output = passthru("sed -e 's/$search/$replace/g' $oldfilename > $newfilename");