我需要将近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行。这样做的最佳方式是什么?
答案 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
然后发出丢失的行应该待解决