使用下面的函数我从表中提取行,对它们进行编码,然后将它们放在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);
}
}
答案 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;
}