去年年底的各種網站帳號資訊的資料庫泄漏,很是給力啊,趁機也下載了幾個資料庫,準備學學資料分析家來分析一下這些帳號資訊。雖然這些資料資訊都已經被“整理”過的,不過自己拿來學習也挺有用的,畢竟有這麼大的資料量。
資料量大帶來的問題就是單個檔案很大,能夠開啟這個檔案相當不容易,記事本就不要指望了,果斷死機。用MSSQL的用戶端也打不開這麼大的SQL檔案,直接報記憶體不足,原因據說是MSSQL在讀取資料的時候,是一次性地將讀取到的資料放在記憶體中,如果資料量過大,而記憶體不足,則會直接導致系統癱掉。
Navicat Premium
這兒推薦一個軟體Navicat Premium,相當給力啊,幾百兆的SQL檔案輕鬆就開啟了,一點都不卡。而且這個用戶端軟體支援MSSQL、MYSQL、Oracle……等等各種資料庫的串連,其它的很多功能就自己慢慢研究了。
雖然用Navicat可以開啟CSDN這個274MB的SQL檔案,但是內容卻是沒意義的,而且也不方便對這些帳號資訊進行查詢、分類、統計等等操作。唯一的方法就是把這些資料一條一條地讀取出來,然後分拆每條記錄的不同片段,再將這些片段以資料欄位的格式存入資料庫,這樣就可以方便以後的使用了。
使用PHP讀取超大檔案
PHP有很多種檔案讀取的方式,根據目標檔案的不同,採取更合適的方法,可有效地提高執行效率。由於CSDN資料庫檔案很大,所以我們盡量不在短時間內全都讀取出來,畢竟每讀取一條資料還要對其分拆和寫入操作。那麼比較合適的方式就是對檔案進行分地區地讀取,通過使用PHP的fseek和fread相結合,即可做到隨意讀取檔案中的某一部份資料,下面是執行個體代碼:
複製代碼 代碼如下:function readBigFile($filename, $count = 20, $tag = "\r\n") {
$content = "";//最終內容
$current = "";//當前讀取內容寄存
$step= 1;//每次走多少字元
$tagLen = strlen($tag);
$start = 0;//起始位置
$i = 0;//計數器
$handle = fopen($filename,'r+');//讀寫入模式開啟檔案,指標指向檔案起始位置
while($i < $count && !feof($handle)) {
fseek($handle, $start, SEEK_SET);//指標設定在檔案開頭
$current = fread($handle,$step);//讀取檔案
$content .= $current;//組合字元串
$start += $step;//依據步長向前移動
//依據分隔字元的長度截取字串最後免得幾個字元
$substrTag = substr($content, -$tagLen);
if ($substrTag == $tag) { //判斷是否為判斷是否是換行或其他分隔字元
$i++;
$content .= "<br />";
}
}
//關閉檔案
fclose($handle);
//返回結果
return $content;
}
$filename = "csdn.sql";//需要讀取的檔案
$tag = "\n";//行分隔字元 注意這裡必須用雙引號
$count = 100;//讀取行數
$data = readBigFile($filename,$count,$tag);
echo $data;
關於函數傳入的變數$tag的值,根據系統不一樣,傳入的值也是有區別的:Windows用”\r\n”,linux/unix用”\n”,Mac OS用”\r”。
程式執行的大概流程:先定義讀取檔案的一些基礎變數,然後開啟檔案,將指標定位在檔案的指定位置,並讀取指定大小的內容。每讀取一次將內容儲存在變數中,直到達到讀取要求的行數或檔案結束。
絕不要假定程式中的一切都將按計劃運行。
根據上面的代碼,雖然能夠得到檔案中指定位置、指定大小的資料,但這整個過程只執行了一次,並不能得到所有的資料。其實要得到所有的資料,可以在這個迴圈的外層再添加判斷檔案是否結束的迴圈,但這很浪費系統資源,甚至由於檔案過大一直沒法讀完而導致PHP執行逾時。另一種方法就是記錄並儲存上次讀取資料後指標所在的位置,然後再次執行該迴圈的時候,將指標定位在上次結束的位置,這樣就不存在一次迴圈要把檔案從頭讀到尾的情況。
其實CSDN這個資料庫我到現在都還沒有匯入資料庫,因為當時泄漏後沒幾天CNBETA上就有一個分析了,呵呵,動作太快了。當看到別人已經做了這個事之後,自動就沒有多少動力來做了,不過為了學習,還是要抽時間把這個事完成了。