1. 程式人生 > >thinkphp5匯入匯出大量csv資料

thinkphp5匯入匯出大量csv資料

在thinkphp/library/think下新建Csv.php檔案:

<?php
/**
 * Created by PhpStorm.
 * User: sunin
 * Date: 2018/10/18
 * Time: 17:42
 */

namespace think;


class Csv
{
    //匯出csv檔案
    public function put_csv(&$data, $titleList = array(), $fileName = '')
    {
        ini_set("max_execution_time", "3600");
        $csvData = '';

        // 標題
        $nums = count($titleList);
        for ($i = 0; $i < $nums - 1; $i++)
        {
            $csvData .= '"' . $titleList[$i] . '",';
        }
        $csvData .= '"' . $titleList[$nums - 1] . "\"\r\n";

        foreach ($data as $key => $row)
        {
            $i = 0;
            foreach ($row as $_key => $_val)
            {
                $_val = str_replace("\"", "\"\"", $_val);
                if ($i < ($nums - 1))
                {
                    $csvData .= '"' . $_val . '",';
                }
                elseif ($i == ($nums - 1))
                {
                    $csvData .= '"' . $_val . "\"\r\n";
                }
                $i++;
            }
            unset($data[$key]);
        }

        $csvData = mb_convert_encoding($csvData, "cp936", "UTF-8");
        $fileName = empty($fileName) ? date('Y-m-d-H-i-s', time()) : $fileName;
        $fileName = $fileName . '.csv';
        header("Content-type:text/csv;");
        header("Content-Disposition:attachment;filename=" . $fileName);
        header('Cache-Control:must-revalidate,post-check=0,pre-check=0');
        header('Expires:0');
        header('Pragma:public');
        echo $csvData;
        exit();
    }

    // csv匯入,支援10W+資料
    public function input_csv($filename,$field,$table) {
        //$field 打散為陣列
        $fieldArr = explode(',', $field);
        //CSV轉陣列 $excelData
        $content = trim(file_get_contents($filename));
        $excelData = explode("\n",$content); //把字串打散為陣列
        //刪除第一行標題
        array_splice($excelData, 0, 1);

        // 將這個大量資料(10W+)的陣列分割成5000一個的小陣列。這樣就一次批量插入5000條資料。mysql 是支援的。
        $chunkData = array_chunk($excelData ,5000);
        $count = count($chunkData);
        for ($i = 0; $i < $count; $i++) {
            $insertRows = array();
            foreach($chunkData[$i] as $value){
                //轉碼,有中文不要用這種方式,會出亂碼
                //$string = mb_convert_encoding(trim(strip_tags($value)), 'utf-8', 'gbk');
                $string = trim(strip_tags($value));//轉碼
                $v = explode(',', $string); //把字串打散為陣列
                $row = array();
                for($j=0;$j<count($fieldArr);$j++){
                    $row[$fieldArr[$j]] = $v[$j];
                }
                $sqlString = "('".implode( "','", $row )."')"; //把陣列元素組合為字串 批量
                $insertRows[] = $sqlString;
            }
            $result = $this->addData($table,$insertRows,$field); //批量將sql插入資料庫。
        }
        return $result;
    }

    public function addData($table,$rows,$field)
    {
        if(empty($rows)){
            return false;
        }
        //資料量較大,採取批量插入
        $data = implode(',', $rows);
        $sql = "INSERT IGNORE INTO $table ($field) VALUES {$data}";
        $result = Db::execute($sql);
        return $result;
    }
}

對應的控制器

use think\Db;
use think\Request;
use think\Csv;

//接受上傳的檔案儲存並匯入資料庫
public function addStory()
    {
        //表名
            $table = 'tablename';
            
            //清空表中資料,自己權衡是否使用
            //$sql = "TRUNCATE TABLE $table";
            //Db::execute($sql);

            //資料庫中欄位名
            $field = 'id,name,bust,bust_position,dialogue';

            //上傳的CSV檔案
            $files = Request::instance()->file("file");
            $info = $files->move(ROOT_PATH . 'public' . DS . 'uploads');
            $filename = ROOT_PATH.'public'.DS.'uploads/'.$info->getSaveName();

            $csv = new Csv();
            $result = $csv->input_csv($filename,$field,$table);
            return $result;
    }

//接受表名並匯出表格
public function putStory()
    {
        //匯出csv表格
        $csv = new Csv();
        //使用原生寫法,thinkPHP查詢方法會有額外資料,導致匯出失敗
        $table = 'tablename';
        $sql = "select * from $table";
        $data = Db::query($sql);
        $titleList = array('id','是否為起始劇情','劇情組名','劇情組簡介','對話方塊資源','對話方塊位置','該劇情組屬於哪一情景');
        $csv->put_csv($data, $titleList);
    }