使用 Guzzle 将 csv 数据作为分块请求发送

Send csv data with Guzzle as a chunked request

我想将 CSV 数据上传到 REST API(仅在特定时间点除外 CSV 数据)。

CSV数据来源为用户上传。上传格式可以是CVS,ODS or XLSX spreadsheet data.

当用户上传 CSV 文件时 - 我只是这样做(简化):

$handle = \fopen($tempFile, 'r');
$client->post('/import', ['body' => $handle]);

这很有效,而且很容易做到。但是,例如,当用户上传 XLSX 时,我目前从第一行开始循环遍历行 sheet 并使用 fputcsv.

创建一个资源
use Box\Spout\Reader\ReaderFactory;

$reader = ReaderFactory::create('xlsx');
$reader->open($tempFile);
$handle = \fopen('php://temp', 'r+');
/** @var $reader \Box\Spout\Reader\XLSX\Reader */
foreach ($reader->getSheetIterator() as $sheet) {
    /** @var $sheet \Box\Spout\Reader\XLSX\Sheet */
    foreach ($sheet->getRowIterator() as $row) {
        \fputcsv($handle, $row);
    }
    break;
}
$reader->close();
$client->post('/import', ['body' => $handle]);

我正在寻找一种在内存消耗和性能方面优化程序(XLSX 导入)的方法。

是否可以使用 guzzle 将 foreach ($sheet->getRowIterator() as $row) 中的请求作为分块请求发送,而无需先使用 fputcsv 创建完整资源?我希望这是有道理的。也许这甚至不是优化...

根据 GuzzleHttp 文档,该库使用 php 个流:

http://docs.guzzlephp.org/en/latest/psr7.html#body

因此您可以为您的请求创建一个流,然后使用 PSR7\StreamIntefrace class 中定义的 write 方法逐行将内容写入其中:

https://github.com/php-fig/http-message/blob/master/src/StreamInterface.php#L115

顺便说一句,正如您在 Guzzle 文档中所读到的那样,流本身使用 php://temp 就像您已经在做的那样,只有优化,如果流大于 2MB,它将交换到磁盘以保留超出的内存.