在工作中, 经常会遇到导入/导出的需求。以下是常用的 PHP 方法, 用于读取 CSV 文件和导出 CSV 文件
读取 CSV 文件
该方法可以分页读取 CSV 文件, 通过设置读取行数和起始行数来控制读取的范围
/**
* 读取 CSV 文件
* @param string $csv_file CSV 文件路径
* @param int $lines 读取的行数
* @param int $offset 起始行数, 从文件的第几行开始读取
* @return array|bool
*/
public function read_csv_lines($csv_file = '', $lines = 0, $offset = 0)
{
if (!$fp = fopen($csv_file, 'r')) {
return false;
}
$i = $j = 0;
// 跳过前 $offset 行
while (false !== ($line = fgets($fp))) {
if ($i++ < $offset) {
continue;
}
break;
}
$data = array();
// 读取接下来的 $lines 行数据
while (($j++ < $lines) && !feof($fp)) {
$data[] = fgetcsv($fp);
}
fclose($fp);
return $data;
}
导出 CSV 文件
导出 CSV 文件可以通过两种方法实现
方法 1: 简单导出 CSV
方法通过简单的输出流导出数据, 每次将数据行直接输出
/**
* 导出 CSV 文件
* @param array $data 数据
* @param array $header_data 首行数据
* @param string $file_name 文件名称
* @return string
*/
public function export_csv_1($data = [], $header_data = [], $file_name = '')
{
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $file_name);
// 输出表头数据
if (!empty($header_data)) {
echo iconv('utf-8', 'gbk//TRANSLIT', '"' . implode('","', $header_data) . '"') . "\n";
}
// 输出数据
foreach ($data as $key => $value) {
$output = array();
$output[] = $value['id'];
$output[] = $value['name'];
echo iconv('utf-8', 'gbk//TRANSLIT', '"' . implode('","', $output) . "\"\n");
}
}
方法 2: 分页导出 CSV
方法则分批输出数据, 以防止内存溢出, 每隔一定行数刷新输出缓冲区, 适用于数据量较大的导出
/**
* 导出 CSV 文件
* @param array $data 数据
* @param array $header_data 首行数据
* @param string $file_name 文件名称
* @return string
*/
public function export_csv_2($data = [], $header_data = [], $file_name = '')
{
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename=' . $file_name);
header('Cache-Control: max-age=0');
// 打开输出流
$fp = fopen('php://output', 'a');
// 输出表头数据
if (!empty($header_data)) {
foreach ($header_data as $key => $value) {
$header_data[$key] = iconv('utf-8', 'gbk', $value);
}
fputcsv($fp, $header_data);
}
// 分批输出数据
$num = 0;
// 每隔 $limit 行刷新一次输出缓冲区, 不要太大, 也不要太小
$limit = 100000;
// 逐行取出数据, 不浪费内存
$count = count($data);
if ($count > 0) {
for ($i = 0; $i < $count; $i++) {
$num++;
// 刷新输出缓冲区, 防止数据过多造成内存溢出
if ($limit == $num) {
ob_flush();
flush();
$num = 0;
}
// 处理当前行数据
$row = $data[$i];
foreach ($row as $key => $value) {
$row[$key] = iconv('utf-8', 'gbk', $value);
}
fputcsv($fp, $row);
}
}
fclose($fp);
}
原文