2011-11-25 73 views
2

使用下面的函數我從表中拉行,對它們進行編碼,然後將它們放入csv格式。我想知道是否有更簡單的方法來防止高內存使用。我不想依賴ini_set。我相信內存消耗是由讀取臨時文件並將其壓縮起來造成的。我很樂意能夠擁有64MB的內存限制。有任何想法嗎?謝謝!php內存限制和讀/寫臨時文件

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); 
    } 
} 

回答

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內存中的字符串。

+0

完美無瑕。工作得很好,剃掉我第20次嘗試的5秒鐘:) – frustratedtech

2

通過stream_get_contents()將整個文件拉入內存可能是什麼讓你失望。您不僅需要保存base64數據(通常比原始內容大約33%),還需要處理csv開銷。如果記憶是一個問題,考慮簡單的調用命令行gzip的應用,而使用gzip壓縮PHP的裏面,是這樣的:

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

而且你或許可以優化的東西DB循環內更好一點,和編碼在-place,而不是建立一個新的數組的每一行:

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

不,這將減少內存使用了 - 它只是數據的單行,所以,除非你處理龐大的記錄字段,它贏得沒有太大的影響。

+0

exec()不存在問題,因爲它通常被禁用。但我正在研究你的意見。謝謝。 – frustratedtech

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; 
} 
1

你可以插入一些潮紅出現,目前整個PHP文件將在內存中,然後在最後沖洗舉行,但是如果你手動

fflush($fh); 

此外,而不是使用gzip壓縮整個文件你可以gzip逐行使用

$gz = gzopen ($fh, 'w9'); 
gzwrite ($gz, $content); 
gzclose ($gz); 

這將逐行寫入打包數據,而不是創建整個文件,然後gzip它。

+0

fflush()對我非常有幫助,謝謝! – Ross