使用PHP将大量数据写入CSV文件

时间:2015-12-04 07:35:40

标签: php performance csv

我需要将近109,392行写入CSV文件,目前我正在这样做

    //open raw memory as file, no need for temp files
    $tempMemory = fopen('php://temp', 'w');

    //default php csv handler
    foreach ($inputArray as $line) {
        fputcsv($tempMemory, $line, $delimiter);
    }

    //rewrind the "file" with the csv lines
    fseek($tempMemory, 0);

    //modify header to be downloadable csv file
    header('Content-Type: application/csv');
    header('Content-Disposition: attachement; filename="' . $outputFileName . '";');

    //send file to browser for download
    fpassthru($tempMemory);

这里的问题是它很慢并且我没有插入所有行。 $inputArray的数组大小为109,392,但生成的CSV文件中只有50K行。这样做的最佳方式是什么?

4 个答案:

答案 0 :(得分:2)

就像现在一样,您首先在内存中生成(或尝试)整个文件,然后才开始将数据发送到浏览器。

由于生成的文件(在内存中?)可能很大,因此至少应检查fputcsv()的返回值。也许它开始是FALSE,这可能是你没有获得所有行的原因。

无论如何,这不是正确的方法(假设有10个用户同时向您的服务器发送相同的请求)。

我不了解php,但生成(按需)和发送此类文件的理想方式是:

  • 首先发送http标头,包括chunked transfer mode的标头。这样你就不需要事先了解文件的大小。

  • 虽然$inputArray中有数据,但填充带有行的缓冲区(例如最大64kB)并将该缓冲区发送到浏览器(也处于分块模式)。您最终可以先压缩数据。

这样浏览器就会立即开始接收数据,而您在服务器上不需要超过64Kb的内存来生成数据。

答案 1 :(得分:1)

尝试直接从mysql获取CSV文件并将其存储在您的系统中,然后允许用户下载它,例如

SELECT order_id,product_name,qty FROM ordersINTO OUTFILE "/tmp/orders.csv"FIELDS TERMINATED BY ','ENCLOSED BY '"'LINES TERMINATED BY '\n';

答案 2 :(得分:1)

您可以直接写入STDOUT,而不是写入'临时'存储文件。

//modify header to be downloadable csv file
header('Content-Type: application/csv');
header('Content-Disposition: attachement; filename="' . $outputFileName . '";');

foreach ($inputArray as $line) {
    fputcsv(STDOUT, $line, $delimiter);
}

这应该快得多.....然而109,392行仍然是很多行。生成这么多数据作为生成整个文件的后台任务会更好,然后从磁盘提供生成的文件。

答案 3 :(得分:0)

我建议不要直接写入php内存,而是写入位于项目根目录中某个公共目录的文件,然后在填写所有行后将请求重定向到该URL domain.com/download_files/generated.csv然后发出丢失的行应该待解决