php内存限制和读/写临时文件

时间:2011-11-25 19:23:19

标签: php memory gzip temp

使用下面的函数我从表中提取行,对它们进行编码,然后将它们放在csv格式中。我想知道是否有更简单的方法来防止高内存使用。我不想依赖ini_set。我相信内存消耗是由读取临时文件和压缩文件引起的。我希望能够限制64mb ram。有任何想法吗?谢谢!

function exportcsv($tables) {
    foreach ($tables as $k => $v) {
        $fh = fopen("php://temp", 'w');
        $sql = mysql_query("SELECT * FROM $v");
        while ($row = mysql_fetch_row($sql)) {
            $line = array();
            foreach ($row as $key => $vv) {
                $line[] = base64_encode($vv);
            }
            fputcsv($fh, $line, chr(9));
        }
        rewind($fh);
        $data = stream_get_contents($fh);
        $gzdata = gzencode($data, 6);
        $fp = fopen('sql/'.$v.'.csv.gz', 'w');
        fwrite($fp, $gzdata);
        fclose($fp);
        fclose($fh);
    }
}

4 个答案:

答案 0 :(得分:2)

通过stream_get_contents()将整个文件拉入内存可能会让你感到害怕。您不仅需要保存base64数据(通常比其原始内容大约33%),您还需要处理csv开销。如果内存有问题,可以考虑简单地调用命令行gzip应用程序而不是在PHP内部进行gzipping,如:

... database loop here ...
exec('gzip yourfile.csv');

你可以在DB循环中更好地优化一些东西,然后就地编码,而不是为每一行构建一个新的数组:

while($row = mysql_fetch_row($result)) {
   foreach ($row as $key => $val) {
       $row[$key] = base64_encode($val);
       fputcsv($fh, $row, chr(9));
   }
}

并不是说这会大大减少内存使用量 - 它只是一行数据,所以除非你处理大量的记录字段,否则它不会产生太大影响。

答案 1 :(得分:2)

未经测试,但希望您理解

function exportcsv($tables) {
    foreach ($tables as $k => $v) {
        $fh = fopen('compress.zlib://sql/' .$v. '.csv.gz', 'w');
        $sql = mysql_unbuffered_query("SELECT * FROM $v");
        while ($row = mysql_fetch_row($sql)) {
            fputcsv($fh, array_map('base64_encode', $row), chr(9));
        }
        fclose($fh);
        mysql_free_result($sql);
    }
}

编辑 - 感兴趣的是使用mysql_unbuffered_query和使用php的压缩流。常规mysql_query()将整个结果集缓冲到内存中。并且在写入文件之前,使用压缩流不必再将数据缓冲到php内存中作为字符串。

答案 2 :(得分:1)

你可以在那里插入一些刷新,目前你的整个php文件将保存在内存中,然后在最后刷新,但是如果你手动

fflush($fh);

也可以使用

逐行gzip,而不是压缩整个文件
$gz = gzopen ( $fh, 'w9' );
gzwrite ( $gz, $content );
gzclose ( $gz );

这将逐行打包数据,而不是创建整个文件,然后再压缩它。

答案 3 :(得分:0)

我发现这个建议是在http://johnibanez.com/node/21

上压缩块

看起来为您的目的修改并不困难。

function gzcompressfile($source, $level = false){ 
    $dest = $source . '.gz'; 
    $mode = 'wb' . $level; 
    $error = false; 

    if ($fp_out = gzopen($dest, $mode)) { 
        if ($fp_in = fopen($source, 'rb')) { 
            while(!feof($fp_in)) {
                gzwrite($fp_out, fread($fp_in, 1024*512)); 
            }
            fclose($fp_in); 
        } 
        else
            $error=true; 

        gzclose($fp_out); 
    } 
    else 
        $error=true; 

    if ($error)
        return false; 
    else
        return $dest;
}