用PHP讀取超大文件的實(shí)例代碼
更新時(shí)間:2012年04月01日 16:09:22 作者:
數(shù)據(jù)量大帶來(lái)的問(wèn)題就是單個(gè)文件很大,能夠打開(kāi)這個(gè)文件相當(dāng)不容易,記事本就不要指望了,果斷死機(jī)
去年年底的各種網(wǎng)站帳號(hào)信息的數(shù)據(jù)庫(kù)泄漏,很是給力啊,趁機(jī)也下載了幾個(gè)數(shù)據(jù)庫(kù),準(zhǔn)備學(xué)學(xué)數(shù)據(jù)分析家來(lái)分析一下這些帳號(hào)信息。雖然這些數(shù)據(jù)信息都已經(jīng)被“整理”過(guò)的,不過(guò)自己拿來(lái)學(xué)習(xí)也挺有用的,畢竟有這么大的數(shù)據(jù)量。
數(shù)據(jù)量大帶來(lái)的問(wèn)題就是單個(gè)文件很大,能夠打開(kāi)這個(gè)文件相當(dāng)不容易,記事本就不要指望了,果斷死機(jī)。用MSSQL的客戶端也打不開(kāi)這么大的SQL文件,直接報(bào)內(nèi)存不足,原因據(jù)說(shuō)是MSSQL在讀取數(shù)據(jù)的時(shí)候,是一次性地將讀取到的數(shù)據(jù)放在內(nèi)存中,如果數(shù)據(jù)量過(guò)大,而內(nèi)存不足,則會(huì)直接導(dǎo)致系統(tǒng)癱掉。
Navicat Premium
這兒推薦一個(gè)軟件Navicat Premium,相當(dāng)給力啊,幾百兆的SQL文件輕松就打開(kāi)了,一點(diǎn)都不卡。而且這個(gè)客戶端軟件支持MSSQL、MYSQL、Oracle……等等各種數(shù)據(jù)庫(kù)的連接,其它的很多功能就自己慢慢研究了。
雖然用Navicat可以打開(kāi)CSDN這個(gè)274MB的SQL文件,但是內(nèi)容卻是沒(méi)意義的,而且也不方便對(duì)這些帳號(hào)信息進(jìn)行查詢、分類、統(tǒng)計(jì)等等操作。唯一的方法就是把這些數(shù)據(jù)一條一條地讀取出來(lái),然后分拆每條記錄的不同片段,再將這些片段以數(shù)據(jù)字段的格式存入數(shù)據(jù)庫(kù),這樣就可以方便以后的使用了。
使用PHP讀取超大文件
PHP有很多種文件讀取的方式,根據(jù)目標(biāo)文件的不同,采取更合適的方法,可有效地提高執(zhí)行效率。由于CSDN數(shù)據(jù)庫(kù)文件很大,所以我們盡量不在短時(shí)間內(nèi)全都讀取出來(lái),畢竟每讀取一條數(shù)據(jù)還要對(duì)其分拆和寫入操作。那么比較合適的方式就是對(duì)文件進(jìn)行分區(qū)域地讀取,通過(guò)使用PHP的fseek和fread相結(jié)合,即可做到隨意讀取文件中的某一部份數(shù)據(jù),下面是實(shí)例代碼:
function readBigFile($filename, $count = 20, $tag = "\r\n") {
$content = "";//最終內(nèi)容
$current = "";//當(dāng)前讀取內(nèi)容寄存
$step= 1;//每次走多少字符
$tagLen = strlen($tag);
$start = 0;//起始位置
$i = 0;//計(jì)數(shù)器
$handle = fopen($filename,'r+');//讀寫模式打開(kāi)文件,指針指向文件起始位置
while($i < $count && !feof($handle)) {
fseek($handle, $start, SEEK_SET);//指針設(shè)置在文件開(kāi)頭
$current = fread($handle,$step);//讀取文件
$content .= $current;//組合字符串
$start += $step;//依據(jù)步長(zhǎng)向前移動(dòng)
//依據(jù)分隔符的長(zhǎng)度截取字符串最后免得幾個(gè)字符
$substrTag = substr($content, -$tagLen);
if ($substrTag == $tag) { //判斷是否為判斷是否是換行或其他分隔符
$i++;
$content .= "<br />";
}
}
//關(guān)閉文件
fclose($handle);
//返回結(jié)果
return $content;
}
$filename = "csdn.sql";//需要讀取的文件
$tag = "\n";//行分隔符 注意這里必須用雙引號(hào)
$count = 100;//讀取行數(shù)
$data = readBigFile($filename,$count,$tag);
echo $data;
關(guān)于函數(shù)傳入的變量$tag的值,根據(jù)系統(tǒng)不一樣,傳入的值也是有區(qū)別的:Windows用”\r\n”,linux/unix用”\n”,Mac OS用”\r”。
程序執(zhí)行的大概流程:先定義讀取文件的一些基礎(chǔ)變量,然后打開(kāi)文件,將指針定位在文件的指定位置,并讀取指定大小的內(nèi)容。每讀取一次將內(nèi)容存儲(chǔ)在變量中,直到達(dá)到讀取要求的行數(shù)或文件結(jié)束。
絕不要假定程序中的一切都將按計(jì)劃運(yùn)行。
根據(jù)上面的代碼,雖然能夠得到文件中指定位置、指定大小的數(shù)據(jù),但這整個(gè)過(guò)程只執(zhí)行了一次,并不能得到所有的數(shù)據(jù)。其實(shí)要得到所有的數(shù)據(jù),可以在這個(gè)循環(huán)的外層再添加判斷文件是否結(jié)束的循環(huán),但這很浪費(fèi)系統(tǒng)資源,甚至由于文件過(guò)大一直沒(méi)法讀完而導(dǎo)致PHP執(zhí)行超時(shí)。另一種方法就是記錄并存儲(chǔ)上次讀取數(shù)據(jù)后指針?biāo)诘奈恢茫缓笤俅螆?zhí)行該循環(huán)的時(shí)候,將指針定位在上次結(jié)束的位置,這樣就不存在一次循環(huán)要把文件從頭讀到尾的情況。
其實(shí)CSDN這個(gè)數(shù)據(jù)庫(kù)我到現(xiàn)在都還沒(méi)有導(dǎo)入數(shù)據(jù)庫(kù),因?yàn)楫?dāng)時(shí)泄漏后沒(méi)幾天CNBETA上就有一個(gè)分析了,呵呵,動(dòng)作太快了。當(dāng)看到別人已經(jīng)做了這個(gè)事之后,自動(dòng)就沒(méi)有多少動(dòng)力來(lái)做了,不過(guò)為了學(xué)習(xí),還是要抽時(shí)間把這個(gè)事完成了。
數(shù)據(jù)量大帶來(lái)的問(wèn)題就是單個(gè)文件很大,能夠打開(kāi)這個(gè)文件相當(dāng)不容易,記事本就不要指望了,果斷死機(jī)。用MSSQL的客戶端也打不開(kāi)這么大的SQL文件,直接報(bào)內(nèi)存不足,原因據(jù)說(shuō)是MSSQL在讀取數(shù)據(jù)的時(shí)候,是一次性地將讀取到的數(shù)據(jù)放在內(nèi)存中,如果數(shù)據(jù)量過(guò)大,而內(nèi)存不足,則會(huì)直接導(dǎo)致系統(tǒng)癱掉。
Navicat Premium
這兒推薦一個(gè)軟件Navicat Premium,相當(dāng)給力啊,幾百兆的SQL文件輕松就打開(kāi)了,一點(diǎn)都不卡。而且這個(gè)客戶端軟件支持MSSQL、MYSQL、Oracle……等等各種數(shù)據(jù)庫(kù)的連接,其它的很多功能就自己慢慢研究了。
雖然用Navicat可以打開(kāi)CSDN這個(gè)274MB的SQL文件,但是內(nèi)容卻是沒(méi)意義的,而且也不方便對(duì)這些帳號(hào)信息進(jìn)行查詢、分類、統(tǒng)計(jì)等等操作。唯一的方法就是把這些數(shù)據(jù)一條一條地讀取出來(lái),然后分拆每條記錄的不同片段,再將這些片段以數(shù)據(jù)字段的格式存入數(shù)據(jù)庫(kù),這樣就可以方便以后的使用了。
使用PHP讀取超大文件
PHP有很多種文件讀取的方式,根據(jù)目標(biāo)文件的不同,采取更合適的方法,可有效地提高執(zhí)行效率。由于CSDN數(shù)據(jù)庫(kù)文件很大,所以我們盡量不在短時(shí)間內(nèi)全都讀取出來(lái),畢竟每讀取一條數(shù)據(jù)還要對(duì)其分拆和寫入操作。那么比較合適的方式就是對(duì)文件進(jìn)行分區(qū)域地讀取,通過(guò)使用PHP的fseek和fread相結(jié)合,即可做到隨意讀取文件中的某一部份數(shù)據(jù),下面是實(shí)例代碼:
復(fù)制代碼 代碼如下:
function readBigFile($filename, $count = 20, $tag = "\r\n") {
$content = "";//最終內(nèi)容
$current = "";//當(dāng)前讀取內(nèi)容寄存
$step= 1;//每次走多少字符
$tagLen = strlen($tag);
$start = 0;//起始位置
$i = 0;//計(jì)數(shù)器
$handle = fopen($filename,'r+');//讀寫模式打開(kāi)文件,指針指向文件起始位置
while($i < $count && !feof($handle)) {
fseek($handle, $start, SEEK_SET);//指針設(shè)置在文件開(kāi)頭
$current = fread($handle,$step);//讀取文件
$content .= $current;//組合字符串
$start += $step;//依據(jù)步長(zhǎng)向前移動(dòng)
//依據(jù)分隔符的長(zhǎng)度截取字符串最后免得幾個(gè)字符
$substrTag = substr($content, -$tagLen);
if ($substrTag == $tag) { //判斷是否為判斷是否是換行或其他分隔符
$i++;
$content .= "<br />";
}
}
//關(guān)閉文件
fclose($handle);
//返回結(jié)果
return $content;
}
$filename = "csdn.sql";//需要讀取的文件
$tag = "\n";//行分隔符 注意這里必須用雙引號(hào)
$count = 100;//讀取行數(shù)
$data = readBigFile($filename,$count,$tag);
echo $data;
關(guān)于函數(shù)傳入的變量$tag的值,根據(jù)系統(tǒng)不一樣,傳入的值也是有區(qū)別的:Windows用”\r\n”,linux/unix用”\n”,Mac OS用”\r”。
程序執(zhí)行的大概流程:先定義讀取文件的一些基礎(chǔ)變量,然后打開(kāi)文件,將指針定位在文件的指定位置,并讀取指定大小的內(nèi)容。每讀取一次將內(nèi)容存儲(chǔ)在變量中,直到達(dá)到讀取要求的行數(shù)或文件結(jié)束。
絕不要假定程序中的一切都將按計(jì)劃運(yùn)行。
根據(jù)上面的代碼,雖然能夠得到文件中指定位置、指定大小的數(shù)據(jù),但這整個(gè)過(guò)程只執(zhí)行了一次,并不能得到所有的數(shù)據(jù)。其實(shí)要得到所有的數(shù)據(jù),可以在這個(gè)循環(huán)的外層再添加判斷文件是否結(jié)束的循環(huán),但這很浪費(fèi)系統(tǒng)資源,甚至由于文件過(guò)大一直沒(méi)法讀完而導(dǎo)致PHP執(zhí)行超時(shí)。另一種方法就是記錄并存儲(chǔ)上次讀取數(shù)據(jù)后指針?biāo)诘奈恢茫缓笤俅螆?zhí)行該循環(huán)的時(shí)候,將指針定位在上次結(jié)束的位置,這樣就不存在一次循環(huán)要把文件從頭讀到尾的情況。
其實(shí)CSDN這個(gè)數(shù)據(jù)庫(kù)我到現(xiàn)在都還沒(méi)有導(dǎo)入數(shù)據(jù)庫(kù),因?yàn)楫?dāng)時(shí)泄漏后沒(méi)幾天CNBETA上就有一個(gè)分析了,呵呵,動(dòng)作太快了。當(dāng)看到別人已經(jīng)做了這個(gè)事之后,自動(dòng)就沒(méi)有多少動(dòng)力來(lái)做了,不過(guò)為了學(xué)習(xí),還是要抽時(shí)間把這個(gè)事完成了。
您可能感興趣的文章:
- PHP搭建大文件切割分塊上傳功能示例
- PHP 讀取和修改大文件的某行內(nèi)容的代碼
- PHP讀取大文件末尾N行的高效方法推薦
- php超快高效率統(tǒng)計(jì)大文件行數(shù)
- PHP讀取大文件的幾種方法介紹
- PHP大文件分割上傳 PHP分片上傳
- php使用file函數(shù)、fseek函數(shù)讀取大文件效率對(duì)比分析
- PHP 讀取大文件并顯示的簡(jiǎn)單實(shí)例(推薦)
- php斷點(diǎn)續(xù)傳之如何分割合并文件
- PHP實(shí)現(xiàn)將多個(gè)文件中的內(nèi)容合并為新文件的方法示例
- PHP合并靜態(tài)文件詳解
- PHP實(shí)現(xiàn)的大文件切割與合并功能示例
相關(guān)文章
laravel使用Faker數(shù)據(jù)填充的實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于laravel使用Faker數(shù)據(jù)填充的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用laravel具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
調(diào)試WordPress中定時(shí)任務(wù)的相關(guān)PHP腳本示例
這篇文章主要介紹了調(diào)試WordPress中定時(shí)任務(wù)的相關(guān)PHP腳本示例,針對(duì)使用Cron API及wp_schedule_event()函數(shù)來(lái)寫的定時(shí)任務(wù),需要的朋友可以參考下2015-12-12
PHP+MySql實(shí)現(xiàn)一個(gè)簡(jiǎn)單的留言板
留言板是接觸WEB開(kāi)發(fā)的基礎(chǔ),寫一個(gè)留言板需要知道前端的一些基礎(chǔ)標(biāo)簽,對(duì)數(shù)據(jù)庫(kù)有一個(gè)了解會(huì)基礎(chǔ)SQL語(yǔ)言,PHP基礎(chǔ)知識(shí),前段基礎(chǔ)+數(shù)據(jù)庫(kù)基礎(chǔ)+PHP基礎(chǔ)=>留言板2020-07-07
Yii2 隊(duì)列 shmilyzxt/yii2-queue 簡(jiǎn)單概述
這篇文章主要介紹了Yii2 隊(duì)列 shmilyzxt/yii2-queue 的簡(jiǎn)單概述,需要的朋友可以參考下2017-08-08
Laravel框架實(shí)現(xiàn)即點(diǎn)即改功能的方法分析
這篇文章主要介紹了Laravel框架實(shí)現(xiàn)即點(diǎn)即改功能的方法,結(jié)合具體實(shí)例形式分析了Laravel框架即點(diǎn)即改功能的實(shí)現(xiàn)原理、步驟及相關(guān)操作技巧,需要的朋友可以參考下2019-10-10
yii2 modal彈窗之ActiveForm ajax表單異步驗(yàn)證
這篇文章主要介紹了yii2 modal彈窗之ActiveForm ajax表單驗(yàn)證的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06
PHP將url生成二維碼并實(shí)現(xiàn)掃碼跳轉(zhuǎn)示例詳解
這篇文章主要為大家介紹了PHP將url生成二維碼并實(shí)現(xiàn)掃碼跳轉(zhuǎn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10

