PHP代码实现csv大文件导入方法往往容易出现超时和返回服务器错误,于是想到了分页的处理方式,具体实现代码如下
<?php require_once 'common.php'; require_once 'config.php'; // 增加超时和内存设置 @ini_set("memory_limit", '-1'); @ini_set("max_execution_time", '0'); // 每页读取行数 $linesPerPage = 10000; // 获取当前页码(假设通过 URL 参数传递页码,默认第 1 页) $pageNum = isset($_GET['page']) ? (int)$_GET['page'] : 1; // 计算当前页的起始行号 $startLine = ($pageNum - 1) * $linesPerPage; try { // CSV 文件路径 $csvFile = '2024mobile.csv'; // 打开 CSV 文件进行读取 if (($handle = fopen($csvFile, 'r')) !== FALSE) { // 跳过表头 if ($pageNum == 1) { fgetcsv($handle); } // 跳过前面的行(直到当前页的起始行) for ($i = 0; $i < $startLine; $i++) { fgetcsv($handle); // 跳过每一行 } // 准备 SQL 插入或更新语句 $sql = "INSERT INTO telecom_info (code, phone_number, province, city, service_provider, area_code, postal_code, area_code_id) VALUES (:code, :phone_number, :province, :city, :service_provider, :area_code, :postal_code, :area_code_id) ON DUPLICATE KEY UPDATE code = VALUES(code), province = VALUES(province), city = VALUES(city), service_provider = VALUES(service_provider), area_code = VALUES(area_code), postal_code = VALUES(postal_code), area_code_id = VALUES(area_code_id)"; // 使用 PDO prepare() 来准备 SQL 语句 $stmt = $pdo->prepare($sql); // 批次大小 $batchSize = 1000; // 每批次处理 1000 条数据 $count = 0; // 记录当前处理的行数 $processedCount = 0; // 当前处理的行数 // 逐行读取 CSV 文件并插入数据 while (($data = fgetcsv($handle)) !== FALSE) { // 尝试检测编码并转换为 UTF-8 foreach ([2, 3, 4] as $index) { // 省区、城市、服务提供商字段 if (!empty($data[$index])) { $encoding = mb_detect_encoding($data[$index], ['UTF-8', 'GBK', 'GB2312', 'ISO-8859-1'], true); $data[$index] = mb_convert_encoding($data[$index], 'UTF-8', $encoding); } } // 从 CSV 行数据中提取字段,并去除前后空格 $code = trim($data[0]); // 号段 $phone_number = trim($data[1]); // 电话号码 $province = trim($data[2]); // 省份 $city = trim($data[3]); // 城市 $service_provider = trim($data[4]); // 服务提供商 $area_code = trim($data[5]); // 区号 $postal_code = trim($data[6]); // 邮政编码 $area_code_id = trim($data[7]); // 区域代码 // 每处理一个批次数据就开启一个事务 if ($count % $batchSize == 0) { // 开始事务 $pdo->beginTransaction(); } // 绑定参数 $stmt->bindParam(':code', $code, PDO::PARAM_STR); $stmt->bindParam(':phone_number', $phone_number, PDO::PARAM_STR); $stmt->bindParam(':province', $province, PDO::PARAM_STR); $stmt->bindParam(':city', $city, PDO::PARAM_STR); $stmt->bindParam(':service_provider', $service_provider, PDO::PARAM_STR); $stmt->bindParam(':area_code', $area_code, PDO::PARAM_STR); $stmt->bindParam(':postal_code', $postal_code, PDO::PARAM_STR); $stmt->bindParam(':area_code_id', $area_code_id, PDO::PARAM_STR); // 执行 SQL 插入或更新操作 $stmt->execute(); // 计数并判断是否达到批次大小 $count++; if ($count % $batchSize == 0) { // 提交当前批次 $pdo->commit(); echo "已处理 $count 条数据\n"; } $processedCount++; // 如果读取的行数等于每页的行数,表示可能还有下一页 if ($processedCount == $linesPerPage) { // 提交最后一批数据 if ($count % $batchSize != 0) { $pdo->commit(); echo "已处理 $count 条数据\n"; } // 关闭文件句柄 fclose($handle); // 实现前端js页面跳转到下一页 echo "已处理 $processedCount 条数据,即将跳转到下一页。"; echo "<script>setTimeout(function(){window.location.href='?page=" . ($pageNum + 1) . "';}, 1000);</script>"; exit; } } // 如果最后一批数据没有达到批次大小,也需要提交 if ($count % $batchSize != 0) { $pdo->commit(); echo "已处理 $count 条数据\n"; } // 关闭文件句柄 fclose($handle); echo "CSV 文件数据已成功插入或更新到数据库!"; } else { echo "无法打开 CSV 文件!"; } } catch (PDOException $e) { // 捕获并显示异常 echo "数据库连接失败: " . $e->getMessage(); }
相关文章