PHP百万级数据导出方案(多csv文件压缩)

首先我们要知道的就是excel与csv区别,常规都是导入导出excel文件的,但是随着文件的增大,内存的消耗以及解析与生成的速率等等,后来逐步采用了csv来替代excel。
下面来说一下PHP如何解析大文件csv以及如何生成csv文件,我来说一下个人的观点:
1.首先解析大文件csv,因为是大文件所以我们要限制它的大小,两层限制,限制解析文件的大小,限制读取的行数,其中我们会用到两个函数:fgetcsv与fgets
下面来说一下这两个函数:
①fgets() 函数从文件指针中读取一行。
fgets(file,length)
参数描述
file必需。规定要读取的文件。
length可选。规定要读取的字节数。默认是 1024 字节。
②fgetcsv() 函数从文件指针中读入一行并解析 CSV 字段。
fgets() 类似,不同的是 fgetcsv() 解析读入的行并找出 CSV 格式的字段,然后返回一个包含这些字段的数组。
fgetcsv() 出错时返回 FALSE,包括碰到文件结束时。
注释:从 PHP 4.3.5 起,fgetcsv() 的操作是二进制安全的。
fgetcsv(file,length,separator,enclosure)
参数描述
file必需。规定要检查的文件。
length可选。规定行的最大长度。必须大于 CVS 文件内最长的一行。
在 PHP 5 中该参数是可选的。在 PHP 5 之前是必需的。
如果忽略(在 PHP 5.0.4 以后的版本中设为 0)该参数的话,那么长度就没有限制,不过可能会影响执行效率。
separator可选。设置字段分界符(只允许一个字符),默认值为逗号。
enclosure可选。设置字段环绕符(只允许一个字符),默认值为双引号。
该参数是在 PHP 4.3.0 中添加的。
下面是所封装的方法:
/**
* import 读取 CSV 文件中的某几行数据
* @param $csvfile csv 文件路径
* @param $lines 读取行数
* @param $offset 起始行数
* @return array
* */
public static function import ( $csvfile , $lines = 0 , $offset = 0 ) {
if (! $fp = fopen( $csvfile , 'r' )) {
return false ;
}
$arr = explode( '.' , $csvfile ) ;
if ( $arr [ 1 ] != 'csv' ){
echo ' 该文件不是 csv 文件,请导入 csv 文件 ' ; exit ;
}
if (filesize( $csvfile ) > 4194304 ){
echo ' csv 文件不能大于 4M' ; exit ;
}
$i = $j = 0 ;
while ( false !== ( $line = fgets( $fp ))) {
if ( $i ++ < $offset ) {
continue ;
}
break ;
}
$data = array () ;
if ( $lines == 0 ){
$lines = count(file( $csvfile )) ;
}
while (( $j ++ < $lines ) && !feof( $fp )) {
$data [] = fgetcsv( $fp ) ;
}
fclose( $fp ) ;
foreach ( $data as $key => $val ){
if ( empty ( $val )){
unset ( $data [ $key ]) ;
}
}
return $data ;
}
2.大文件csv生成,打包成压缩包供下载:
因为时间问题,暂无法解答,代码如下
/**
* 输出 UTF-8 编码的 csv 文件
* @param array $head 标题
* @param $data 数据
* @param string $mark 文件名(压缩包内)
* @param string $fileName 文件名(一个文件)
*/
public static function export ( array $head , $data , $mark = 'meeboo_statistics_info' , $fileName = "info.csv" ){
set_time_limit( 0 ) ;
$sqlCount = count( $data ) ;
// 输出 Excel 文件头,可把 user.csv 换成你要的文件名
header( 'Content-Type: application/vnd.ms-excel;charset=utf-8' ) ;
header( 'Content-Disposition: attachment;filename="' . $fileName . '"' ) ;
header( 'Cache-Control: max-age=0' ) ;
$sqlLimit = 30000 ; // 每次只从数据库取 30000 条以防变量缓存太大
// 每隔 $limit 行,刷新一下输出 buffer ,不要太大,也不要太小
$limit = 30000 ;
// buffer 计数器
$cnt = 0 ;
$fileNameArr = array () ;
// 逐行取出数据,不浪费内存
for ( $i = 0 ; $i < ceil( $sqlCount / $sqlLimit ) ; $i ++) {
$fp = fopen( $mark . '_' . $i . '.csv' , 'w' ) ; // 生成临时文件
$fileNameArr [] = $mark . '_' . $i . '.csv' ;
// 将数据通过 fputcsv 写到文件句柄
fputcsv ( $fp , $head ) ;
$dataArr = array () ;
$arr = $data ;
if ( $i == 0 ){
foreach ( $arr as $key => $val ){
if ( $key > $sqlLimit - 1 ){
unset ( $arr [ $key ]) ;
}
$dataArr = $arr ;
}
} else {
foreach ( $data as $k => $v ){
if ( $k <=( $sqlLimit *( $i )- 1 ) || $k >( $sqlLimit *( $i + 1 )- 1 )){
unset ( $data [ $k ]) ;
}
$dataArr = $data ;
}
}
foreach ( $dataArr as $a ) {
$cnt ++ ;
if ( $limit == $cnt ) {
// 刷新一下输出 buffer ,防止由于数据过多造成问题
ob_flush() ;
flush() ;
$cnt = 0 ;
}
fputcsv ( $fp , $a ) ;
}
fclose( $fp ) ; // 每生成一个文件关闭
}
// 进行多个文件压缩
$zip = new \ZipArchive() ;
$filename = $mark . ".zip" ;
$zip -> open ( $filename , \ZipArchive:: CREATE ) ; // 打开压缩包
foreach ( $fileNameArr as $file ) {
$zip -> addFile ( $file , basename( $file )) ; // 向压缩包中添加文件
}
$zip -> close () ; // 关闭压缩包
foreach ( $fileNameArr as $file ) {
unlink( $file ) ; // 删除 csv 临时文件
}
// 下载
self :: export_csv ( $filename ) ;
}
 
/**
* // 输出压缩文件提供下载
* @param $filename
*/
private static function export_csv ( $filename ){
header( "Cache-Control: max-age=0" ) ;
header( "Content-Description: File Transfer" ) ;
header( 'Content-disposition: attachment; filename=' . basename( $filename )) ; // 文件名
header( "Content-Type: application/zip" ) ; // zip 格式的
header( "Content-Transfer-Encoding: binary" ) ;
header( 'Content-Length: ' . filesize( $filename )) ;
@readfile( $filename ) ; // 输出文件 ;
unlink( $filename ) ; // 删除压缩包临时文件
}

微信扫描二维码,关注我的公众号,一起讨论技术,共勉。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A_青涩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值