php 使用 yield 批量处理文件并读取大数据导入数据库

生成器的核心是一个 yield 关键字,使用yield php会返回一个属于Generator类的对象,这个对象可以使用foreach()函数进行迭代,
官方文档解释:yield提供了一种更容易的方法来实现简单的迭代对象,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。

<?php
declare (strict_types = 1);

namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use think\facade\Db;
use think\facade\Log;

class Test extends Command
{
    protected function configure()
    {
        // 指令配置
        $this->setName('test')
            ->setDescription('the test command');
    }

    protected function execute(Input $input, Output $output)
    {
        set_time_limit(0);
        ini_set("memory_limit", "-1");
        $dir = app()->getRuntimePath() . '资源文件夹';

        try {
        	// 获取遍历的全部文件
            $list = $this->openAllDir($dir);

            $i = 1;
            foreach ($list as $item) {
                if (file_exists($item) && is_file($item)) {
                    // 这里开始读取文件内容
                    $output->writeln("正在读取第 {$i} 个文件 {$item}");
                    $res = $this->readImportFile($item);
                    $is_err = false;
                    // 处理读取到的数据并插入数据库
                    foreach ($res as $k => $re) {
                        if (empty($re[0])) {
                            continue;
                        }
                        foreach ($re as &$v) {
                            $v = $v && is_string($v) ? addslashes($v) : '';
                        }
                        unset($v);
                        if (isset($re[15])) {
                            $re[15] = intval($re[15]);
                        }
                        // 去掉重复名称数据
                        $exists = Db::name('xxx')->where('name', $re[0])->count();
                        if ($exists) {
                            continue;
                        }

                        $sql = "INSERT INTO `xxx`(`id`, `name`, `business_status`, `legal_representative`, `registered_capital`, `paid_in_capital`, `date_of_incorporation`, `approval_date`, `business_term`, `province`, `city`, `county`, `credit_code`, `identification_number`, `registration_no`, `organization_code`, `number_of_insured_persons`, `company_type`, `industry`, `name_used_before`, `registered_address`, `new_report_address`, `website`, `contact_number`, `other_number`, `email`, `other_email`, `nature_of_business`) VALUES (null , '{$re[0]}', '{$re[1]}', '{$re[2]}', '{$re[3]}', '{$re[4]}', '{$re[5]}', '{$re[6]}', '{$re[7]}', '{$re[8]}', '{$re[9]}', '{$re[10]}', '{$re[11]}', '{$re[12]}', '{$re[13]}', '{$re[14]}', '{$re[15]}', '{$re[16]}', '$re[17]', '$re[18]', '$re[19]', '$re[20]', '$re[21]', '$re[22]', '$re[24]', '$re[25]', '$re[26]', '$re[27]');";

                        $res = Db::execute($sql);
                        if (!empty($res)) {
                            $output->writeln("{$item} 文件添加第 ". ($k+1) ." 条记录成功!" . PHP_EOL);
                        } else {
                            $is_err = true;
                            $output->writeln("{$item} 文件添加第 ". ($k+1) ." 条记录添加失败!记录log" . PHP_EOL);
                        }
                    }
                    if ($is_err) {
                        $output->writeln("读取第 {$i} 个文件 {$item} 失败!");
                    }
                    $i++;
                }

            }

        } catch (\Exception $e) {
            $output->writeln('error:'. $e->getMessage());
        }

        // 指令输出
        $output->writeln('end');
    }

	// 读取文件
    protected function readImportFile($file)
    {
        $inputFileType = IOFactory::identify($file);
        $objReader = IOFactory::createReader($inputFileType);
        $worksheetNames = $objReader->listWorksheetNames($file);
        // 只读取表格数据,忽略里面的各种格式,否则会内存耗尽
        $objReader->setReadDataOnly(TRUE);
        $objReader->setLoadSheetsOnly($worksheetNames[0]);
        $objPHPExcels = $objReader->load($file);
        $maxCol = $objPHPExcels->getSheet(0)->getHighestColumn(); // 总列数
        $maxRow = $objPHPExcels->getSheet(0)->getHighestRow(); // 总行数

        for ($i = 4; $i <= $maxRow; $i++) {
            // 读取一行
            yield $objPHPExcels->getSheet(0)->rangeToArray('A' . $i . ':' . $maxCol . $i)[0];
        }
    }

	// 遍历文件夹,因为 yield 好像无法递归所以一个一个文件夹遍历
    protected function openAllDir($dir)
    {
        // 读取文件夹下全部文件
        if (is_dir($dir)) {
            if ($dh = opendir($dir)) {
                while (($file = readdir($dh)) !== false) {
                    if ($file != '.' && $file != '..') {
                        $name = $dir . '/' . $file;
                        if (is_dir($name)) {

                            if ($dh2 = opendir($name)) {
                                while (($file2 = readdir($dh2)) !== false) {
                                    if ($file2 != '.' && $file2 != '..') {
                                        $name2 = $name . '/' . $file2;
                                        if (is_dir($name2)) {

                                            if ($dh3 = opendir($name2)) {
                                                while (($file3 = readdir($dh3)) !== false) {
                                                    if ($file3 != '.' && $file3 != '..') {
                                                        $name3 = $name2 . '/' . $file3;
                                                        if (is_dir($name3)) {

                                                            if ($dh4 = opendir($name3)) {
                                                                while (($file4 = readdir($dh4)) !== false) {
                                                                    if ($file4 != '.' && $file4 != '..') {
                                                                        $name4 = $name3 . '/' . $file4;
                                                                        if (is_dir($name4)) {
                                                                            // end
                                                                        } else {
                                                                            if (strrchr($name4, '.') == '.xlsx') {
                                                                                yield $name4;
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }

                                                        } else {
                                                            if (strrchr($name3, '.') == '.xlsx') {
                                                                yield $name3;
                                                            }
                                                        }
                                                    }
                                                }
                                            }

                                        } else {
                                            if (strrchr($name2, '.') == '.xlsx') {
                                                yield $name2;
                                            }
                                        }
                                    }
                                }
                            }

                        } else {
                            if (strrchr($name, '.') == '.xlsx') {
                                yield $name;
                            }
                        }
                    }
                }
                closedir($dh);
            }
        }
    }
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值