php生成csv文件和Excel文件

php生成csv文件和Excel文件

生成csv文件

什么是csv

csv文件是一种文件格式,它以.csv为后缀,双击打开它,默认会使用Excel(或WPS表格)打开,但它的缺点是,无法做任何格式的设置,比如字体放大、加粗等等,就连居中,或者把单元格拉宽都不行(你打开之后可以拉宽,但无法保存这个宽度,下次打开还是一样窄)。

csv是comma seperated value的首字母缩写,它的意思是“逗号分隔的值”,因为它真的就是用逗号分隔的值,它格式如下

值1,值2,值3,值4,值5
值1,值2,值3,值4,值5
值1,值2,值3,值4,值5

所以理论上,我们只需要组装成以上格式的字符串(其实就是:列用,分隔,行用\n行隔),再写入一个.csv后缀的文件就可以了,但实际上这样大概率是会乱码的(中文一定会乱码),我们还需要在该字符串前面加个BOM头才不会乱码。

什么是BOM?

在UCS(Universal Character Set, 通用字符集)编码中,有一个编码叫“Zero Width No-Break Space”(零宽无间断间隔),编码为U+FEFF,该编码是一个没有被使用的(不存在对应字符)的编码,UCS规范建议我们在传输字节流前先传输该“字符”(它实际是一个不存在的字符)。这样如果接收者收到FEFF,就表明这个字节流是大端的;如果收到FFFE,就表明这个字节流是小端的。因此字符”Zero Width No-Break Space”实际上是被作为“字节顺序标记”来使用的,而“字节顺序标记”的英文为Byte Order Mark,简称BOM。

但UTF-8编码是不需要BOM来表示字节序的,那这个编码在UTF-8编码中有什么用呢?其实是没什么用的,但是有些公司就是特立独行,没错,我说的就是微软,微软Windows系统自带的记事本,就会自动给UTF-8编码文件的开头添加个BOM头,另外微软的Excel也会这样,这就是为什么我们不给csv添加BOM头的时候,用Excel打开后中文会乱码,因为它识别不出那是UTF-8编码。

但是FEFF编码成UTF-8,它会变成EF BB BF,具体原理请看这里,总之我们要在UTF-8编码文件中添加BOM头,就必须添加EF BB BF这三个字节(每两位十六进制数表示1个字节,即8位,因为一个十六进制可表示4位二进制)。

实例代码

<?php
$arr = [
    ['张三', '男', '20'],
    ['李四', '男', '21'],
    ['王五', '女', '22'],
    ['赵六', '女', '23'],
];

// pack()函数用于把数据转换为二进制字符串,C是格式,表示unsigned char,三个C是因为后面有三个数据
$bom = pack('CCC', 0xef, 0xbb, 0xbf);
$header = '姓名, 性别, 年龄' . PHP_EOL;
$csvLine = $bom . $header;
foreach($arr as $val){
    $csvLine .= implode(',', $val) . PHP_EOL;
}
file_put_contents("/path/to/users.csv", $csvLine);

最终效果

生成Excel文件

方法一:手动保存

生成csv文件后打开,然后文件→另存为.xlsx格式即可。
优点:省内存。

方法二:使用PhpSpreadsheet

最初php生成Excel文件是使用PHPExcel库的,但该库2017年被弃用,2019年被归档,它的文档上有写:

The project has not be maintained for years and must not be used anymore. All users must migrate to its direct successor PhpSpreadsheet, or another alternative.
翻译:该项目已多年无人维护,因此不再推荐使用。所有用户都应该迁移到它的直接继承者PhpSpreadsheet,或者其它的替代。

PhpSpreadsheetREADME后面有写

PhpSpreadsheet is the next version of PHPExcel. It breaks compatibility to dramatically improve the code base quality (namespaces, PSR compliance, use of latest PHP language features, etc.).

Because all efforts have shifted to PhpSpreadsheet, PHPExcel will no longer be maintained. All contributions for PHPExcel, patches and new features, should target PhpSpreadsheet master branch.

也就是说,现在的phpExcel库已经换成了PhpSpreadsheet,这是它的:官方文档

优点:直接生成xlsx格式表格,但如果行数太多(比如我试过十几二十万行的),则需要内存比较多。


以下为测试使用PhpSpreadsheet代码

在本地终端合适的目录中执行以下命令

# 创建并进入文件夹
mkdir php-excel-test && cd php-excel-test

# 使用composer安装phpspreadsheet包
composer require phpoffice/phpspreadsheet

# 创建一个index.php文件
touch index.php

index.php内容如下

<?php
require_once 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', 'Hello World !');

$writer = new Xlsx($spreadsheet);
// 记得修改路径为你电脑中的实际路径
$writer->save('/path/to/hello-world.xlsx');

最终结果

实例代码

实例代码1:新建test1.php文件,把以下内容添加到test1.php中,把最后一行保存路径修改为你本地的实际路径

<?php
require_once 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

$arr = [
    ['张三', '男', '20'],
    ['李四', '男', '21'],
    ['王五', '女', '22'],
    ['赵六', '女', '23'],
];

$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();

$worksheet->setCellValue('A1', '姓名');
$worksheet->setCellValue('B1', '性别');
$worksheet->setCellValue('C1', '年龄');

foreach($arr as $key=>$val){
    $cellNum = $worksheet->getHighestRow() + 1;
    $worksheet->setCellValue('A'.$cellNum, $val[0]);
    $worksheet->setCellValue('B'.$cellNum, $val[1]);
    $worksheet->setCellValue('C'.$cellNum, $val[2]);
}

$writer = new Xlsx($spreadsheet);
// 记得修改路径为你电脑中的实际路径
$writer->save('/path/to/users1.xlsx');

在终端中运行以下命令生成users1.xlsx文件,当然也可以在浏览器中访问(请自己搭建环境)

php test1.php

实例代码2:新建test2.php文件,把以下内容添加到test2.php中,把最后一行保存路径修改为你本地的实际路径

<?php
require_once 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

$users = [
    ['张三', '男', '20'],
    ['李四', '男', '21'],
    ['王五', '女', '22'],
    ['赵六', '女', '23'],
];

$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();

// 把表头添加到数组第一行
$users = array_merge([['姓名', '性别', '年龄']], $users);

// 一次性写入多行
$worksheet->fromArray($users, null, 'A' . $worksheet->getHighestRow() + 1);

$writer = new Xlsx($spreadsheet);

// 记得修改路径为你电脑中的实际路径
$writer->save('/path/to/users2.xlsx');

在终端中运行以下命令生成users2.xlsx文件,当然也可以在浏览器中访问(请自己搭建环境)

php test2.php

最终结果

如果报内存不足,可以在php文件第一行增加以下代码来暂时增加php允许使用的内存

ini_set('memory_limit', '512M');
打赏

订阅评论
提醒
guest

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x

扫码在手机查看
iPhone请用自带相机扫
安卓用UC/QQ浏览器扫

php生成csv文件和Excel文件