PHP匯入大量CSV資料

Yoooooo發表於2022-02-17

前言

網上有很多介紹大量上傳資料的,感覺都是一個抄一個,這是自己寫的處理方式,在一些專案中已經應用.
主要利用 yield 完成檔案讀取,這個重點看會了,其他基本就很簡單.

程式碼部分

一.controller寫法

//獲取請求的引數
$arrayParams = Request::all();
$objCsvFile = $arrayParams['csv_file'];
$strRealPath = $objCsvFile->getRealPath();//tmp路徑, 這裡可以先儲存到自己預定路徑,再進行讀取

//**************重點在這一步********************//
$glob = CommonUtilFunction::readPathCsvFile($strRealPath);
//********************************************//

$intRowNum = 0;
while($glob->valid()) {
    $arrayNewLineData = [];
    $intRowNum++;
    if (1 === $intRowNum) {
        //第一行跳過,一般是標題
        $glob->next();
        continue;
    }
    $arrayLineData = $glob->current();

    //處理空字串 空行
    /**
    * 一般csv有兩種行資料可以被認為是空行
    * 第一種 ',,,,,,,,,,,,,,,,,,,,,,,,,,',類似這種純逗號沒有任何資料
    * 第二種 '                          ',是真的空行,什麼也沒有
    * 處理完成返回一個統一的陣列 []
    */
    $arrayLineData = CommonUtilFunction::dealCsvLineData($arrayLineData);
    //跳過空行
    if (true === empty($arrayLineData)) {
        $glob->next();
        continue;
    }

    //自己的程式碼邏輯
    ...

    // 避免意外錯誤
    unset($arrayNewLineData);
    $glob->next(); // 處理下一行資料
}

二.yield讀取資料以及處理空行方法

/**
* @description 迭代器讀取csv檔案
* @param $strCsvPath
* @return \Generator
*/
public static function readPathCsvFile($strCsvPath)
{
    if ($handle = fopen($strCsvPath, 'r')) {
        while (!feof($handle)) {
            yield fgetcsv($handle);
        }
        fclose($handle);
    }
}


/**
* @description 處理c單行資訊
* @param $arrData
* @return \Generator
*/public static function dealCsvLineData($arrData = [])
{
    $arrAfterData = [];
    if (false === empty($arrData)) {
        //去除每個字串 前後空格
        foreach ($arrData as &$colData) {
            //檢測對應編碼格式 csv檔案格式Shift-JIS
            $strEncodeType = mb_detect_encoding($colData, ['UTF-8', 'Shift-JIS']);
            //如果認為utf-8格式不用轉碼, shift-jis格式需要轉為utf8格式
            if ('SJIS' === $strEncodeType) {
                //jis=>utf8
                $colData = mb_convert_encoding($colData, 'UTF-8', 'Shift-JIS');
            }
            $colData = trim($colData);
        }  
        //去除空行
        $isEmptyRow = true;
        foreach ($arrData as $item) {
            if ('' !== $item) {
                $isEmptyRow = false;
                break;
            } 
        }  
        if (false === $isEmptyRow) {
            $arrAfterData = $arrData;
        }
    } 
    return $arrAfterData;
}

結論

使用yield可以很大程度上減低伺服器開銷,壓力在資料庫方面.上限沒有測試過,不過1萬條資料是很輕鬆.

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章