版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第PHP超低內(nèi)存遍歷目錄文件和讀取超大文件的方法這不是一篇教程,這是一篇筆記,所以我不會很系統(tǒng)地論述原理和實(shí)現(xiàn),只簡單說明和舉例。
前言
我寫這篇筆記的原因是現(xiàn)在網(wǎng)絡(luò)上關(guān)于PHP遍歷目錄文件和PHP讀取文本文件的教程和示例代碼都是極其低效的,低效就算了,有的甚至好意思說是高效,實(shí)在辣眼睛。
這篇筆記主要解決這么幾個問題:
PHP如何使用超低內(nèi)存快速遍歷數(shù)以萬計的目錄文件?
PHP如何使用超低內(nèi)存快速讀取幾百M(fèi)B甚至是GB級文件?
順便解決哪天我忘了可以通過搜索引擎搜到我自己寫的筆記來看看。(因?yàn)樾枰狿HP寫這兩個功能的情況真的很少,我記性不好,免得忘了又重走一遍彎路)
遍歷目錄文件
網(wǎng)上關(guān)于這個方法的實(shí)現(xiàn)大多示例代碼是glob或者opendir+readdir組合,在目錄文件不多的情況下是沒問題的,但文件一多就有問題了(這里是指封裝成函數(shù)統(tǒng)一返回一個數(shù)組的時候),過大的數(shù)組會要求使用超大內(nèi)存,不僅導(dǎo)致速度慢,而且內(nèi)存不足的時候直接就崩潰了。
這時候正確的實(shí)現(xiàn)方法是使用yield關(guān)鍵字返回,下面是我最近使用的代碼:
functionglob2foreach($path,$include_dirs=false){
$path=rtrim($path,'/*');
if(is_readable($path)){
$dh=opendir($path);
while(($file=readdir($dh))!==false){
if(substr($file,0,1)=='.')
continue;
$rfile="{$path}/{$file}";
if(is_dir($rfile)){
$sub=glob2foreach($rfile,$include_dirs);
while($sub-valid()){
yield$sub-current();
$sub-next();
if($include_dirs)
yield$rfile;
}else{
yield$rfile;
closedir($dh);
//使用
$glob=glob2foreach('/var/www');
while($glob-valid()){
//當(dāng)前文件
$filename=$glob-current();
//這個就是包括路徑在內(nèi)的完整文件名了
//echo$filename;
//指向下一個,不能少
$glob-next();
yield返回的是生成器對象(不了解的可以先去了解一下PHP生成器),并沒有立即生成數(shù)組,所以目錄下文件再多也不會出現(xiàn)巨無霸數(shù)組的情況,內(nèi)存消耗是低到可以忽略不計的幾十kb級別,時間消耗也幾乎只有循環(huán)消耗。
讀取文本文件
讀取文本文件的情況跟遍歷目錄文件其實(shí)類似,網(wǎng)上教程基本上都是使用file_get_contents讀到內(nèi)存里或者fopen+feof+fgetc組合即讀即用,處理小文件的時候沒問題,但是處理大文件就有內(nèi)存不足等問題了,用file_get_contents去讀幾百M(fèi)B的文件幾乎就是自殺。
這個問題的正確處理方法同樣和yield關(guān)鍵字有關(guān),通過yield逐行處理,或者SplFileObject從指定位置讀取。
逐行讀取整個文件:
functionread_file($path){
if($handle=fopen($path,'r')){
while(!feof($handle)){
yieldtrim(fgets($handle));
fclose($handle);
//使用
$glob=read_file('/var/www/hello.txt');
while($glob-valid()){
//當(dāng)前行文本
$line=$glob-current();
//逐行處理數(shù)據(jù)
//$line
//指向下一個,不能少
$glob-next();
通過yield逐行讀取文件,具體使用多少內(nèi)存取決于每一行的數(shù)據(jù)量有多大,如果是每行只有幾百字節(jié)的日志文件,即使這個文件超過100M,占用內(nèi)存也只是KB級別。
但很多時候我們并不需要一次性讀完整個文件,比如當(dāng)我們想分頁讀取一個1G大小的日志文件的時候,可能想第一頁讀取前面1000行,第二頁讀取第1000行到2000行,這時候就不能用上面的方法了,因?yàn)槟欠椒m然占用內(nèi)存低,但是數(shù)以萬計的循環(huán)是需要消耗時間的。
這時候,就改用SplFileObject處理,SplFileObject可以從指定行數(shù)開始讀取。下面例子是寫入數(shù)組返回,可以根據(jù)自己業(yè)務(wù)決定要不要寫入數(shù)組,我懶得改了。
functionread_file2arr($path,$count,$offset=0){
$arr=array();
if(!is_readable($path))
return$arr;
$fp=newSplFileObject($path,'r');
//定位到指定的行數(shù)開始讀
if($offset)
$fp-seek($offset);
$i=0;
while(!$fp-eof()){
//必須放在開頭
$i++;
//只讀$count這么多行
if($i$count)
break;
$line=$fp-current();
$line=trim($line);
$arr[]=$line;
//指向下一個,不能少
$fp-next();
return$arr;
以上所說的都是文件巨大但是每一行數(shù)據(jù)量都很小的情況,有時候情況不是這樣,有時候是一行數(shù)據(jù)也有上百M(fèi)B,那這該怎么處理呢?
如果是這種情況,那就要看具體業(yè)務(wù)了,SplFileObject是可以通過fseek定位到字符位置(注意,跟seek定位到行數(shù)不一樣),然后通過fread讀取指定長度的字符。
也就是說通過fseek和fread是可以實(shí)現(xiàn)分段讀取一個超長字符串的,也就是可以實(shí)現(xiàn)超低內(nèi)存處理,但是具體要怎么做還是得看具體業(yè)務(wù)要求允許你怎么做。
復(fù)制大文件
順便說下PHP復(fù)制文件,復(fù)制小文件用copy函數(shù)是沒問題的,復(fù)制大文件的話還是用數(shù)據(jù)流好,例子如下:
functioncopy_file($path,$to_file){
if(!is_readable($path))
returnfalse;
if(!is_dir(dirname($to_file)))
@mkdir(dirname($to_file).'/',0747,TRUE);
if(
($handle1=fopen($path,'r'))
($handle2=fopen($to_file,'w'))
stream_copy_to_stream($handle1,$handle2);
fclose($handle1);
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 養(yǎng)老院老人訪客管理制度
- 養(yǎng)老院老人生活娛樂活動組織人員管理制度
- 養(yǎng)老院老人康復(fù)理療制度
- 養(yǎng)老院綠化環(huán)境維護(hù)制度
- 養(yǎng)老院員工培訓(xùn)與考核制度
- 公共交通運(yùn)營成本控制制度
- 攝影技術(shù)與技巧
- 2026年志愿服務(wù)管理知識考試題含答案
- 2026年跨境電商促銷活動設(shè)計邏輯測試題目及答案
- 工藝技術(shù)創(chuàng)新大賽
- 標(biāo)準(zhǔn)維修維護(hù)保養(yǎng)服務(wù)合同
- 專題08解題技巧專題:圓中輔助線的作法壓軸題三種模型全攻略(原卷版+解析)
- GB/T 4706.9-2024家用和類似用途電器的安全第9部分:剃須刀、電理發(fā)剪及類似器具的特殊要求
- 2019年急性腦梗死出血轉(zhuǎn)化專家共識解讀
- 電力工程有限公司管理制度制度范本
- 科研倫理與學(xué)術(shù)規(guī)范-課后作業(yè)答案
- 安全防范系統(tǒng)安裝維護(hù)員題庫
- mbd技術(shù)體系在航空制造中的應(yīng)用
- 苗木育苗方式
- 通信原理-脈沖編碼調(diào)制(PCM)
- 省直單位公費(fèi)醫(yī)療管理辦法實(shí)施細(xì)則
評論
0/150
提交評論