php fwritecsv,PHP学习笔记---实现导出csv功能(附带打包zip教程)

对于许多的从事数据智能开发的同僚来说,从库中提取出数据后进行数据整理并且导出csv文件的功能是很常见的,导出一个csv文件方便用其他的数据工具进行分析。所以在这里分享一下我在工作过程中实现导出csv文件功能的历程与所获。

前言

首先,我被告知需要在laravel框架中实现下载接口这个任务时,整个人是懵逼的,完全不知道怎么着手去实现这个功能,但是对于一个理工科生来说,碰到问题并不可怕,剥丝抽茧,一步一步来。我分析,既然要实现下载功能接口,首先需要做的就是提供一个接口,而如何做一个接口我在<>中已介绍,向前端提供一个URI即达到了接口的意义,其次是如何实现下载,最后是如何写入一个csv文件,本篇文章就从后两个方向介绍,并且最后附带PHP中文件打包功能的实现介绍

本来想打包功能单独写一篇博客的,后来发现这个功能实现比较简单,而深层次的我也暂时不会,就附带本篇文章最后了

下载

一、通过传递HTTP报头实现下载

首先在度娘上找到的实现下载的方式之一:是通过向浏览器传递HTTP报头,告诉浏览器这个URI的相关动作让浏览器去实现。

HTTP报头是HTTP协议的一个部分,一般上用于客户端和服务端之间握手时的通信,通俗的理解就是 http服务器和客户端(一般为浏览器)之间数据传输之前的对话,告诉浏览器你想干什么。

而在PHP中实现HTTP报头参数传递功能的是header()方法,header() 函数向客户端发送原始的 HTTP 报头。其中认识到一点很重要,即必须在任何实际的输出被发送之前调用 header() 函数,例如在调用header()函数前不要写print_r()或var_dump()等函数。

传递报头参数的代码:

header("Content-type:text/csv");

header("Content-Disposition:attachment;filename=" . $start_date . '~' . $end_date . '_fare.csv');

header('Cache-Control:must-revalidate,post-check=0,pre-check=0');

header('Expires:0');

header('Pragma:public');

其中第一行是告诉浏览器我需要导出文件,格式是csv,在Content-type这个参数类型中可以指定许多的导出文本的格式,例如rar、zip这样的压缩包格式

传递这样的报头后,导出的文件的内容将是你在调用该header()函数的方法内的return值,例如return 123;则csv文件中就是123。

这种方式可以实现下载,但是总归看上去不太好看,如此优秀的laravel框架怎么可能会不涉及到下载方法的封装呢,于是后来使用了另一种方法。

二、通过response方法实现下载

在看了其他前辈写的代码中,我发现有一行代码

return reponse()->download($file)

看单词意思也知道这行代码是起什么作用的。Response是laravel框架中的门面(facade),在这个框架中是可以直接引用调用的功能

例如:

//响应重定向

Route::get('example/test24', function(){

return Redirect::to('example/test21')->with('username', 'xiaoming');

});

//定制HTTP响应

Route::get('example/test21', function(){

return Response::make('内容不存在', 404);

});

//响应视图

Route::get('example/test22', function(){

return Response::view('test22');

});

以上的例子是response在封闭函数中的直接调用,在其他的地方自然也是可以直接使用的,而下载文件就可以使用Response::download()方法

我们先看一下这个的源代码:

/**

* Create a new file download response.

*

* @param \\SplFileInfo|string $file

* @param string $name

* @param array $headers

* @param string|null $disposition

* @return \\Symfony\\Component\\HttpFoundation\\BinaryFileResponse

*/

public function download($file, $name = null, array $headers = [], $disposition = 'attachment');

可以看到这个下载方法的参数,有$file, $name = null, array $headers = [], $disposition = 'attachment',后面都有默认值,可以不传递,也可以用于参数扩展,利用这个方法就可以实现下载

例如:

public function getDownload()

{

//PDF file is stored under project/public/download/info.pdf

$file= public_path(). "/download/info.pdf";

$headers = array(

'Content-Type: application/pdf',

);

return Response::download($file, 'filename.pdf', $headers);

}

由此处的header()可以看出是要求下载一个pdf文件,而在laravel 5框架中使用此功能还可以使用

return response()->download($file, 'filename.pdf', $headers);

这种方式,功能是一样的,其中也可以只指定第一个参数,这样下载的文件就是你的文件之前指定好的类型。

写入csv文件方法

介绍了如何实现下载的两种方法,现在来说一下如何将数据写入csv文件

字符串连接方法

首先要知道,csv文件的内容其实就是一串拼接起来的字符串,起始指定好表头字符串,后面就以该表头的顺序依次拼接数据即可,只是在表头和每一行数据的末尾都添加一个换行符\\n来达到表格对齐的效果即可。

例如:

$head_str = "日期,姓名,年龄,学校\\n";

$cnt = count($data);

for ($i =0;$i

$tmp = implode(",",$data[$i]);

$head_str .= $tmp."\\n";

}

其中$data是从库中取出的数据的二维数组,而每一个第一层索引指向的就是对应的每一行数据,然后利用for循环遍历取出每一行数据进行拼接。

这一种方法是和传递HTTP报头实现下载的方法配合使用效果更好,因为在拼接完成后直接在方法内return $head_str,就能将整个数据内容读入到了下载的csv文件中。当然,也可以使用fwrite()方法写入一个新文件$file,然后利用response->download($file)方法下载该文件即可。

export()方法

后来发现,每次这样拼接数据非常的麻烦,可以写一个公共的方法,以便在其他地方实现类似的功能时可以直接调用

public static function exportData($data = array(), $title = [])

{

$new_data = [];

if (!empty($data)) {

if(empty($title))

{

foreach ($data as $key => $val) {

$new_data[$key] = isset($val) ? mb_convert_encoding($val, 'gbk', 'utf-8') : '';

}

} else {

foreach ($title as $key => $val) {

$new_data[$key] = isset($data[$key]) ? mb_convert_encoding($data[$key], 'gbk', 'utf-8') : '';

}

}

$str = implode(',', $new_data);

fwrite(self::$fp, $str."\\n");

}

}

这个方法的实现原理是将数据进行转码处理然后利用fwrite()方法写入一个新文件。其中self::$fp是指定的文件的路径,这个php手册上看一下fwrite()方法的介绍就能晓得参数的意思。写入了新的文件后就可以再通过reponse->download()方法来下载了。

php文件打包教程

在数据量非常庞大时,一次性取出大量的数据然后写入csv文件再下载的这个流程是不适用的,因为数据量庞大会导致取数时间很长,命令运行超出内存。此时可以采用的方法就是将大量的数据按时间维度写入多个csv文件,然后再根据需要的时间区间将多个csv文件打包下载即可,所以在这也讲一下我如何实现文件打包。

在php中,利用的是ZipArchive()类,通过这个类的实例化来实现打包。

依然是感兴趣的同学自行在php手册上学习

代码:

//获取zip包名

$zip_file = $save_path . '/' . $start_date . '-' . $end_date . '.zip';

if (file_exists($zip_file)) {

return response()->download($zip_file);

}

//文件打包

$zip = new ZipArchive();

if ($zip -> open($zip_file, ZipArchive::CREATE) == true) {

foreach ($file_dir as $file) {

if (file_exists($file)) {

$zip -> addFile($file, basename($file));

}

}

}

$zip -> close();

这样就实现了打包,其中$file_dir变量是你要打包的文件的路径数组,里面包含所有你想打包的文件路径,$zip_file变量是你想打包成zip文件的包的路径+名称。

有的同学在使用此方法时有时会不管用,以我的经验,一般都是文件的路径不正确,或者是没有指定绝对路径

注意:在$zip -> addFile()方法中不要使用路径变量拼接,最好在使用该方法前就写好路径。使用了拼接不会报错,但是依然会文件添加不进去,这里是一个大坑,我找了好久才发现。

最后:本人新手程序员,一起进步!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值