fputcsv — нехватка памяти при создании больших файлов

Я создаю иногда большие CSV-файлы из информации БД для пользователей, чтобы затем загрузить — 100 КБ или более строк. Похоже, я столкнулся с проблемой памяти во время создания CSV на некоторых из более крупных файлов. Вот пример того, как я в настоящее время занимаюсь созданием CSV.

Есть ли способ обойти это? Первоначально имел 32 МБ и изменил это до 64 МБ и до сих пор проблема.

//columns array
$log_columns = array(
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9'
);

//results from the db
$results = $log_stmt->fetchAll(PDO::FETCH_ASSOC);

$log_file = 'test.csv';

$log_path = $_SERVER['DOCUMENT_ROOT'].'/../user-data/'.$_SESSION['user']['account_id'].'/downloads/';

// if location does not exist create it
if(!file_exists($log_path))
{
mkdir($log_path, 0755, true);
}

// open file handler
$fp = fopen($log_path.$log_file, 'wb');

// write the csv column titles / labels
fputcsv($fp, $log_columns);

//are there any logs?
if($results)
{

//write the rows
foreach($results as $row)
{

//rows array
$log_rows = array(
$row['1'],
$row['2'],
$row['3'],
$row['4'],
$row['5'],
$row['6'],
$row['7'],
$row['8'],
$row['9']
);
//write the rows
$newcsv = fputcsv($fp, $log_rows);

}//end foreach
}
// there were no results so just return an empty log
else
{
$newcsv = fputcsv($fp, array('No results found.') );
}

//close handler
fclose($fp);

// if csv was created return true
if($newcsv)
{
return true;
}

ОБНОВИТЬ :

Использование цикла while и выборки вместо foreach и fetchAll все равно приводит к ошибке памяти.

while($result = $log_stmt->fetch(PDO::FETCH_ASSOC))

Как это возможно, если я загружаю только одну строку за раз?

ОБНОВЛЕНИЕ 2:

Я проследил это до цикла while, используя memory_get_usage();

echo (floor( memory_get_usage() / 1024) ).' kb<br />';

Перед запуском цикла while результат составляет 4658 КБ, а затем для каждой итерации цикла while он увеличивается на 1 КБ каждые 2-3 цикла, пока не достигнет максимально допустимого объема памяти 32748 КБ.

Что я могу сделать, чтобы решить эту проблему?

ОБНОВЛЕНИЕ 3:

Сегодня я больше поиграл с этим … то, как это работает, не имеет для меня особого смысла — я могу только предположить, что это странное поведение с php GC.

сценарий 1: Мой запрос получает все 80 тыс. Строк и использует цикл while для их вывода. Объем используемой памяти составляет около 4500 КБ после получения запроса, а затем увеличивается на 1 КБ каждые две-три строки, которые выводятся в цикле. Память не высвобождается как никогда, и в какой-то момент происходит сбой без достаточного количества памяти.

while($results = $log_stmt->fetch(PDO::FETCH_ASSOC))
{
echo $results['timestamp'].'<br/>';
}

сценарий 2: Мой запрос теперь зацикливается и получает 1000 строк за раз с циклом, который выводит каждую строку. Максимальная память составляет 400 Кб, поскольку она зацикливается и завершает весь вывод без проблем с памятью.

Для этого примера я просто использовал счетчик 80 раз, так как знаю, что нужно извлечь более 80 тыс. Строк. На самом деле мне бы пришлось сделать это иначе.

$t_counter = 0;

while($t_counter < 80)
{
//set bindings
$binding = array(
'cw_start' => $t_counter * 1000,
//some other bindings...
);
$log_stmt->execute($binding);

echo $t_counter.' after statement '.floor( memory_get_usage() / 1024 ).' kb<br />';

while($results = $log_stmt->fetch(PDO::FETCH_ASSOC))
{
echo $results['capture_timestamp'].'<br/>';
}

echo $t_counter.' after while'.floor( memory_get_usage() / 1024 ).' kb<br />';

$t_counter++;
}

Поэтому я предполагаю, что мой вопрос заключается в том, почему в первом сценарии увеличивается использование памяти, и ничего не выходит? В цикле while нет новых переменных, и все «используется повторно». Точно такая же ситуация происходит во втором сценарии просто внутри другого цикла.

0

Решение

fetchAll извлекает все записи, которые не просто запрашивают его и выполняют цикл while с fetch, тогда ему не нужно загружать весь набор результатов в память.

http://php.net/manual/en/pdostatement.fetch.php

1

Другие решения

Тогда я думаю, что вы должны попробовать прочитать файлы в битах. Прочитайте их и добавьте в один CSV-файл, чтобы освободить память во время процесса.
Вы могли бы сделать подсчет (*), но попробуйте найти общее количество до многократного сбора

0

Я сам использую php’s csv, я даже использую его как систему базы данных (nosql)
пытаться

CSV-код для чтения
<?php
$CSVfp = fopen("filename.csv", "r");
if($CSVfp !== FALSE) {
$con=1;
while(! feof($CSVfp))
{
do something
}?>

**csv code for writting **

<?php
$list = array
(
"edmond,dog,cat,redonton",
"Glenn,Quagmire,Oslo,Norway",
);$file = fopen("filename.csv","w");foreach ($list as $line)

{fputcsv($file,explode(',',$line));}fclose($file); ?>
-1
По вопросам рекламы [email protected]