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();
}相关文章