實(shí)時(shí)生成并下載大數(shù)據(jù)量的EXCEL文件?
對(duì)于任何一個(gè)網(wǎng)站肯定是少不了下載功能,常見的下載功能有圖片、視頻、Excel表格,如果文件比較小的話,那么不會(huì)遇到任何的問題,但是當(dāng)文件信息而超過了PHP的最大內(nèi)存,那么在這個(gè)時(shí)候它就會(huì)有的內(nèi)存溢出的問題。
那么它們是因?yàn)槭裁炊l(fā)生的?對(duì)于這個(gè)過程的原理才是我們應(yīng)該真正要去弄明白的事情
下載大數(shù)據(jù)量的EXCEL文件為何要報(bào)錯(cuò)?PHP在下載大Excel表格的時(shí)候,那么首先它是需要去把MySQL的數(shù)據(jù)從硬盤上面讀取到內(nèi)存,但讀取它是一次性載入到我們的內(nèi)存,如果說它一次性載入的數(shù)據(jù)量遠(yuǎn)遠(yuǎn)大于最大內(nèi)存,然后再來執(zhí)行瀏覽器的業(yè)務(wù)下載。那么這個(gè)時(shí)候它就會(huì)發(fā)生我們這個(gè)內(nèi)存溢出。
就比如:說我們現(xiàn)在有100M的數(shù)據(jù)量,但是我們PHP內(nèi)存最大只有64M,那么這個(gè)它肯定是裝不了的,我們可以把那個(gè)內(nèi)存比喻為一個(gè)水杯,這個(gè)水杯的容量比喻為內(nèi)存,現(xiàn)在杯子最大容量為64L。你要存放100L。肯定放不下
大事化小,小事化了。拆分成段從上面可以看到文件下載,它是分為兩步,首先是載入內(nèi)存然后執(zhí)行瀏覽器的輸出下載,那么既然大型文件一次性載入不了,那可以采用 “大事化小,小事化了”思路,我們可以實(shí)現(xiàn)邊寫邊下載,也就是分批次的讀取與寫入。
因?yàn)橛脩舻脑挘灰罱K拿到這個(gè)文件就可以,對(duì)于瀏覽器的下載原理不需要關(guān)心。只需要給到文件下載提示給用戶即可,然后后端在實(shí)時(shí)的分批次的寫入到要下載的文件當(dāng)中。
實(shí)現(xiàn)思路步驟:
1、一設(shè)置瀏覽器下載Excel需要的Header
2、打開 php://output 流,并設(shè)置寫入文件句柄。
注:(php://output,是一個(gè)可寫的輸出流,允許程序像操作文件一樣將輸出寫入到輸出流中,PHP會(huì)把輸出流中的內(nèi)容發(fā)送給web服務(wù)器并返回給發(fā)起請(qǐng)求的瀏覽器)
3、獲取數(shù)據(jù)庫(kù)所有數(shù)據(jù)量,并設(shè)置每次查詢的條數(shù),通過這兩個(gè)值計(jì)算分批查詢的次數(shù)
4、基于分批查詢的次數(shù)循環(huán)查詢數(shù)據(jù)庫(kù),然后寫入到文件中,同時(shí)清除本次操作變量?jī)?nèi)存,刷新緩沖到瀏覽器,讓瀏覽器的文件始終實(shí)時(shí)保持到最新的大小
注:刷新用ob_flush、flush()PHP的I/O流在這里我們用到了PHP的一個(gè)IO的輸入輸出,也就是我們常用的
php://input php://output。php://input
php://input可以讀取原始的POST數(shù)據(jù)。相較于$HTTP_RAW_POST_DATA而言,它給內(nèi)存帶來的壓力較小,并且不需要特殊的php.ini設(shè)置。php://input不能用于enctype=multipart/form-data”.
注:HTTP_RAW_POST_DATA 在PHP7已經(jīng)被廢棄,它不是$_POST額php://output
php://output 是一個(gè)只寫的數(shù)據(jù)流, 允許你以 print 和 echo 一樣的方式 寫入到輸出緩沖區(qū)。
綜上:實(shí)現(xiàn)思維與原理很重要如有感悟,歡迎關(guān)注額。(* ̄︶ ̄)