這篇文章介紹的內容是關於php csv 匯出,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下
最近公司專案要求把資料除了頁面輸出也希望有匯出功能,雖然之前也做過幾個導出功能,但這次數據量相對比較大,差不多一天數據就20W條,要求導7天或者30天,那麼數據量就輕鬆破百萬了甚至破千萬,因此開發的過程中發現了一些大數據導出的坑,在此跟大家分享一下,互相學習。
set_time_limit – 設定腳本最大執行時間:
此配置一般PHP預設是30秒,如果你是資料小的,可能就不會發現有該設定問題,但如果你資料達到了百萬級導出,往往30秒是不夠的,因此你需要在你的腳本中加入set_time_limit(0),讓該腳本沒有執行時間現在
#memory_limit – PHP的記憶體限定:
這個配置一般php預設是128M,如果之前做過小數據的朋友可能也會動過這個配置就能解決許多問題,或許有人想,你大數據也把這個調大不就行了嗎?那麼真的是too young too native了,你本地能設置1G或者無限製或許真的沒問題,但是正式場,你這麼搞遲早會出事的,一個PHP程序佔那麼大的內存的空間,如果你叫你公司維幫忙調一下配置,估計運維一定很不情願,伺服器硬體這麼搞也是太奢侈了。所以說,我們要盡量避免調大該設定。
既然是導出數據,大夥們當然馬上想到了excel格式了,多方便查看數據呀,然而萬萬沒想到excel也是有脾氣的呀!
表格資料限制:
Excel 2003及以下的版本。一张表最大支持65536行数据,256列。 Excel 2007-2010版本。一张表最大支持1048576行,16384列。
1
(後來看了一些文章發現PHPExcel也有解決方案,PHPExcel_Settings::setCacheStorageMethod方法更改緩衝方式來減少記憶體的使用)
ob_flush();flush();
具体说明介绍:PHP flush()与ob_flush()的区别详解
EXCEL查看CSV文件数量限制:
大多数人看csv文件都是直接用EXCEL打开的。额,这不就是回到EXCEL坑中了吗?EXCEL有数据显示限制呀,你几百万数据只给你看104W而已。什么?你不管?那是他们打开方式不对而已?不好不好,我们解决也不难呀,我们也把数据分割一下就好了,再分开csv文件保存,反正你不分割数据变量也会内存溢出。
分析完上面那些坑,那么我们的解决方案来了,假设数据量是几百万。
1、那么我们要从数据库中读取要进行数据量分批读取,以防变量内存溢出,
2、我们选择数据保存文件格式是csv文件,以方便导出之后的阅读、导入数据库等操作。
3、以防不方便excel读取csv文件,我们需要104W之前就得把数据分割进行多个csv文件保存
4、多个csv文件输出给用户下载是不友好的,我们还需要把多个csv文件进行压缩,最后提供给一个ZIP格式的压缩包给用户下载就好。
//导出说明:因为EXCEL单表只能显示104W数据,同时使用PHPEXCEL容易因为数据量太大而导致占用内存过大, //因此,数据的输出用csv文件的格式输出,但是csv文件用EXCEL软件读取同样会存在只能显示104W的情况,所以将数据分割保存在多个csv文件中,并且最后压缩成zip文件提供下载 function putCsv(array $head, $data, $mark = 'attack_ip_info', $fileName = "test.csv") { set_time_limit(0); $sqlCount = $data->count(); // 输出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 = 100000;//每次只从数据库取100000条以防变量缓存太大 // 每隔$limit行,刷新一下输出buffer,不要太大,也不要太小 $limit = 100000; // buffer计数器 $cnt = 0; $fileNameArr = array(); // 逐行取出数据,不浪费内存 for ($i = 0; $i < ceil($sqlCount / $sqlLimit); $i++) { $fp = fopen($mark . '_' . $i . '.csv', 'w'); //生成临时文件 // chmod('attack_ip_info_' . $i . '.csv',777);//修改可执行权限 $fileNameArr[] = $mark . '_' . $i . '.csv'; // 将数据通过fputcsv写到文件句柄 fputcsv($fp, $head); $dataArr = $data->offset($i * $sqlLimit)->limit($sqlLimit)->get()->toArray(); 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临时文件 } //输出压缩文件提供下载 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); //删除压缩包临时文件 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
其实上面代码还是有优化的空间的,比如说用异常捕捉,以防因为某些错误而导致生成了一些临时文件又没有正常删除,还有PHPexcel的缓存设置也许能解决内存溢出问题,可以生成一个EXCEL文件多个工作表的形式,这样对于文件阅读者来说更友好。
以上便是本人对PHP大数据导出的见解,希望能帮到您们,同时不足的地方请多多指教!
————————————————————————————————————
2017年12月17日
PS:最近了解其实关于内存溢出的问题,用迭代器来处理会方便多了。
版权声明:每一篇原创文章都是我的心血,欢迎转载,但请转载前留个评论,感谢您的支持!!! https://blog.csdn.net/Tim_phper/article/details/77581071
相关推荐:
以上是php csv 匯出的詳細內容。更多資訊請關注PHP中文網其他相關文章!