gpt4 book ai didi

php - 从外部 FTP 服务器读取 > 1GB GZipped CSV 文件

转载 作者:行者123 更新时间:2023-12-03 16:48:24 26 4
gpt4 key购买 nike

在我的 Laravel 应用程序的计划任务中,我正在外部 FTP 服务器上读取几个大的 gzipped CSV 文件,大小从 80mb 到 4gb,包含我根据产品属性存储在我的数据库中的产品。
我遍历要导入的产品提要列表,但每次都返回一个 fatal error :“已用尽 536870912 字节的允许内存大小”。我可以提高 fgetcsv 的长度参数函数来自 1000100000这解决了较小文件(< 500mb)的问题,但对于较大的文件,它将返回 fatal error 。
是否有一种解决方案可以让我下载或解压缩 .csv.gz 文件、读取行(按批次或逐行)并将产品插入到我的数据库中而不会耗尽内存?

$feeds = [
"feed_baby-mother-child.csv.gz",
"feed_computer-games.csv.gz",
"feed_general-books.csv.gz",
"feed_toys.csv.gz",
];

foreach ($feeds as $feed) {
$importedProducts = array();
$importedFeedProducts = 0;

$csvfile = 'compress.zlib://ftp://' . config('app.ftp_username') . ':' . config('app.ftp_password') . '@' . config('app.ftp_host') . '/' . $feed;

if (($handle = fopen($csvfile, "r")) !== FALSE) {
$row = 1;
$header = fgetcsv($handle, 1, "|");

while (($data = fgetcsv($handle, 1000, "|")) !== FALSE) {
if($row == 1 || array(null) !== $data){ $row++; continue; }

$product = array_combine($header, $data);
$importedProducts[] = $product;
}

fclose($handle);
} else {
echo 'Failed to open: ' . $feed . PHP_EOL;
continue;
}

// start inserting products into the database below here
}

最佳答案

问题可能不是 gzip 文件本身,
当然你可以下载它,然后在处理它,这将保持相同的问题。
因为您将所有产品加载到一个数组中(内存)

$importedProducts[] = $product;
您可以将此行注释掉,并查看它是否会达到您的内存限制。
通常我会创建一个像 addProduct($product) 这样的方法来处理它的内存安全。
然后,您可以在进行批量插入之前从那里决定最大数量的产品。为了达到最佳速度..我通常使用 1000 和 5000 行之间的东西。
例如
class ProductBatchInserter
{
private $maxRecords = 1000;
private $records = [];

function addProduct($record) {
$this->records[] = $record;
if (count($this->records) >= $this->maxRecords) {
EloquentModel::insert($this->records);
$this->records = [];
}
}
}
但是我通常不会将它作为单个类来实现,但是在我的项目中,我曾经将它们集成为 BulkInsertable 特性,可以在任何 Eloquent 模型上使用。
但这应该给你一个方向,如何避免内存限制。
或者,更简单但明显更慢,只需插入您现在将其分配给数组的行。
但这会给您的数据库带来可笑的负载,而且速度会非常慢。
如果 GZIP 流是瓶颈
正如我所料,这不是问题,但如果是这样,那么您可以使用 gzopen()
https://www.php.net/manual/en/function.gzopen.php
并将 gzopen 句柄嵌套为 fgetcsv 的句柄。
但是我希望您正在使用的流处理程序已经为您这样做了。
如果没有,我的意思是这样的:
$input = gzopen('input.csv.gz', 'r'); 


while (($row = fgetcsv($input)) !== false) {
// do something memory safe, like suggested above
}
如果您无论如何都需要下载它,有很多方法可以做到,但请确保您使用内存安全的东西,例如 fopen/fgets 或 guzzle 流,并且不要尝试使用诸如 file_get_contents() 之类的东西将其加载到内存中

关于php - 从外部 FTP 服务器读取 > 1GB GZipped CSV 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62955829/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com