使用 StreamedResponse 下载 CSV 在几行后停止
Downloading CSV with StreamedResponse stops after several rows
我有一个 MongoDB 集合,其中包含几千个条目,我想将其下载为 CSV 文件。
我有一些代码基本上执行以下操作;控制器方法使用 Doctrine ODM 查询数据库中的所有记录。然后将返回的游标馈送到 StreamedResponse。在 StreamedResponse 中,我遍历光标并将每条记录输出为 CSV 中的一行。
以下代码有效,并下载了一个文件。只是,它包含不超过 60 行。可能是什么原因导致它在该点停止流式传输,而光标计数表明有 2670 个结果?
// Get all available bookings
$cursor = $this
->get('doctrine_mongodb')
->getRepository('FooBundle:Booking')
->getQueryBuilder()
->getQuery()
->execute();
$response = new StreamedResponse(function () use ($cursor) {
$handle = fopen('php://output', 'r+');
$headerPrinted = false;
// Calling $cursor->count() here returns 2670
foreach ($cursor as $result) {
// Transform the Booking object to a flat array.
$data = $this->constructRow($result);
// Print CSV header
if (!$headerPrinted) {
fputcsv($handle, array_keys($data), ';', '"');
$headerPrinted = true;
}
// Add a line in the csv file.
fputcsv($handle, $data, ';', '"');
}
fclose($handle);
});
$response->headers->set('Content-Type', 'application/force-download');
$response->headers->set('Content-Disposition', 'attachment; filename="bookings.csv"');
return $response;
据我所知,没有代码在流式传输时在内存中累积数据。我使用 Symfony 2.7、Doctrine MongoDB ODM 1.0.3 和 PHP 5.5.9,memory_limit 为 256M。
听起来这与您 php.ini
中的内存限制有关
ini_set('memory_limit','16M');
提高一下,看看你得到多少行
如评论中所述,问题与游标结果上的不可删除对象有关。
对于捕获异常并写入正确的数据,您可以捕获异常。需要重写循环以捕获异常。例如,您可以执行一个 do while 循环,如下所示:
do {
try
{
// this could rise an exception
$result = $cursor->getNext()
// Transform the Booking object to a flat array.
$data = $this->constructRow($result);
// Print CSV header
if (!$headerPrinted) {
fputcsv($handle, array_keys($data), ';', '"');
$headerPrinted = true;
}
// Add a line in the csv file.
fputcsv($handle, $data, ';', '"');
} catch (\Exception $e)
{
// do nothing and process next element
}
}
while($cursor->hasNext())
我还建议使用一个库来管理 CSV 写入,例如:
希望对您有所帮助
我有一个 MongoDB 集合,其中包含几千个条目,我想将其下载为 CSV 文件。
我有一些代码基本上执行以下操作;控制器方法使用 Doctrine ODM 查询数据库中的所有记录。然后将返回的游标馈送到 StreamedResponse。在 StreamedResponse 中,我遍历光标并将每条记录输出为 CSV 中的一行。
以下代码有效,并下载了一个文件。只是,它包含不超过 60 行。可能是什么原因导致它在该点停止流式传输,而光标计数表明有 2670 个结果?
// Get all available bookings
$cursor = $this
->get('doctrine_mongodb')
->getRepository('FooBundle:Booking')
->getQueryBuilder()
->getQuery()
->execute();
$response = new StreamedResponse(function () use ($cursor) {
$handle = fopen('php://output', 'r+');
$headerPrinted = false;
// Calling $cursor->count() here returns 2670
foreach ($cursor as $result) {
// Transform the Booking object to a flat array.
$data = $this->constructRow($result);
// Print CSV header
if (!$headerPrinted) {
fputcsv($handle, array_keys($data), ';', '"');
$headerPrinted = true;
}
// Add a line in the csv file.
fputcsv($handle, $data, ';', '"');
}
fclose($handle);
});
$response->headers->set('Content-Type', 'application/force-download');
$response->headers->set('Content-Disposition', 'attachment; filename="bookings.csv"');
return $response;
据我所知,没有代码在流式传输时在内存中累积数据。我使用 Symfony 2.7、Doctrine MongoDB ODM 1.0.3 和 PHP 5.5.9,memory_limit 为 256M。
听起来这与您 php.ini
中的内存限制有关ini_set('memory_limit','16M');
提高一下,看看你得到多少行
如评论中所述,问题与游标结果上的不可删除对象有关。 对于捕获异常并写入正确的数据,您可以捕获异常。需要重写循环以捕获异常。例如,您可以执行一个 do while 循环,如下所示:
do {
try
{
// this could rise an exception
$result = $cursor->getNext()
// Transform the Booking object to a flat array.
$data = $this->constructRow($result);
// Print CSV header
if (!$headerPrinted) {
fputcsv($handle, array_keys($data), ';', '"');
$headerPrinted = true;
}
// Add a line in the csv file.
fputcsv($handle, $data, ';', '"');
} catch (\Exception $e)
{
// do nothing and process next element
}
}
while($cursor->hasNext())
我还建议使用一个库来管理 CSV 写入,例如:
希望对您有所帮助