亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

從外部 FTP 服務器讀取 > 1GB GZipped CSV 文件

從外部 FTP 服務器讀取 > 1GB GZipped CSV 文件

PHP
呼啦一陣風 2023-08-11 11:00:24
在我的 Laravel 應用程序的計劃任務中,我正在外部 FTP 服務器上讀取幾個大型 gzip 壓縮的 CSV 文件,大小從 80mb 到 4gb 不等,其中包含我根據產品屬性存儲在數據庫中的產品。我循環遍歷要導入的產品源列表,但每次都會返回致命錯誤:“允許的內存大小 536870912 字節已耗盡”。我可以提高fgetcsv函數的長度參數,從而1000解決100000較小文件(< 500mb)的問題,但對于較大文件,它將返回致命錯誤。是否有一種解決方案允許我下載或解壓縮 .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}
查看完整描述

1 回答

?
HUH函數

TA貢獻1836條經驗 獲得超4個贊

問題可能不是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 特征。


但這應該給你一個方向,告訴你如何避免內存限制。


或者,更簡單,但速度明顯慢,只需插入現在將其分配給數組的行。但這會給你的數據庫帶來巨大的負載,而且速度會非常慢。


如果 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() 這樣的東西將其加載到內存中


查看完整回答
反對 回復 2023-08-11
  • 1 回答
  • 0 關注
  • 131 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號