使用下面的函数,我从表中提取行,对它们进行编码,然后将它们放入csv格式。我想知道是否有一种更简单的方法来防止高内存使用。我不想依赖于ini_set。我认为内存消耗是由于读取临时文件并将其压缩造成的。我希望能够有64mb的内存限制。什么好主意吗?谢谢!
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);
}
}
未经测试,但希望您能理解
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内存中。
通过stream_get_contents()
将整个文件拉入内存可能是杀死您的原因。您不仅需要保存base64数据(通常比原始内容大33%),还需要处理csv开销。如果内存是一个问题,可以考虑简单地调用命令行gzip应用程序,而不是在PHP内部进行gzip,如:
... 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));
}
}
并不是说这将减少内存的使用-它只是一个单行数据,所以除非你处理的是巨大的记录字段,否则它不会有太大的影响。
你可以在那里插入一些刷新,目前你的整个php文件将保存在内存中,然后在最后刷新,但是如果你手动
fflush($fh);
也可以使用
逐行gzip来代替对整个文件进行gzip。$gz = gzopen ( $fh, 'w9' );
gzwrite ( $gz, $content );
gzclose ( $gz );
这将逐行写入打包的数据,而不是创建整个文件然后压缩它。
我在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;
}