文章詳細介紹了csv文件在php中快速導入到mysql數據庫中的例子,雖然從最簡單的幾百MB的到最后使用插件實現幾個GB數據導入中間有一些嗑碰了,但結果還是好的.
對于數百萬條數據量的CSV文件,文件大小可能達到數百M,如果簡單讀取的話很可能出現超時或者卡死的現象.
為了成功將CSV文件里的數據導入數據庫,分批處理是非常必要的,下面這個函數是讀取CSV文件中指定的某幾行數據,代碼如下:
- /**
- * csv_get_lines 讀取CSV文件中的某幾行數據
- * @param $csvfile csv文件路徑
- * @param $lines 讀取行數
- * @param $offset 起始行數
- * @return array
- * */
- function csv_get_lines($csvfile, $lines, $offset = 0) {
- if(!$fp = fopen($csvfile, 'r')) {
- //開源代碼Vevb.com
- return false;
- }
- $i = $j = 0;
- while (false !== ($line = fgets($fp))) {
- if($i++ < $offset) {
- continue;
- }
- break;
- }
- $data = array();
- while(($j++ < $lines) && !feof($fp)) {
- $data[] = fgetcsv($fp);
- }
- fclose($fp);
- return $data;
- }
- //調用方法:
- $data = csv_get_lines('path/bigfile.csv', 10, 2000000);
- print_r($data);
函數主要采用行定位的思路,通過跳過起始行數來實現文件指針定位,至于數據如何入庫本文不再詳細講述.
上述函數對500M以內的文件進行過測試,運行通暢,對于1GB的文件發現有點慢了,于是再接著找方法.
如何快速完整的操作大文件仍然還存在一些問題.
1、如何快速獲取CSV大文件的總行數?
辦法一:直接獲取文件內容,使用換行符進行拆分得出總行數,這種辦法對小文件可行,處理大文件時不可行;
辦法二:使用fgets一行一行遍歷,得出總行數,這種辦法比辦法一好一些,但大文件仍有超時的可能;
辦法三:借助SplFileObject類,直接將指針定位到文件末尾,通過SplFileObject::key方法獲取總行數,這種辦法可行,且高效。
具體實現方法,代碼如下:
- $csv_file = 'path/bigfile.csv';
- $spl_object = new SplFileObject($csv_file, 'rb');
- $spl_object->seek(filesize($csv_file));
- echo $spl_object->key();
2、如何快速獲取CSV大文件的數據?
仍然使用PHP的SplFileObject類,通過seek方法實現快速定位,代碼如下:
- $csv_file = 'path/bigfile.csv';
- $start = 100000; // 從第100000行開始 m.survivalescaperooms.com讀取
- $num = 100; // 讀取100行
- $data = array();
- $spl_object = new SplFileObject($csv_file, 'rb');
- $spl_object->seek($start);
- while ($num-- && !$spl_object->eof()) {
- $data[] = $spl_object->fgetcsv();
- $spl_object->next();
- }
- print_r($data);
綜合上面兩點,整理成一個csv文件讀取的類,代碼如下:
- class CsvReader {
- private $csv_file;
- private $spl_object = null;
- private $error;
- public function __construct($csv_file = '') {
- if($csv_file && file_exists($csv_file)) {
- $this->csv_file = $csv_file;
- }
- }
- public function set_csv_file($csv_file) {
- if(!$csv_file || !file_exists($csv_file)) {
- $this->error = 'File invalid';
- return false;
- }
- $this->csv_file = $csv_file;
- $this->spl_object = null;
- }
- public function get_csv_file() {
- return $this->csv_file;
- }
- private function _file_valid($file = '') {
- $file = $file ? $file : $this->csv_file;
- if(!$file || !file_exists($file)) {
- return false;
- }
- if(!is_readable($file)) {
- return false;
- }
- return true;
- }
- private function _open_file() {
- if(!$this->_file_valid()) {
- $this->error = 'File invalid';
- return false;
- }
- if($this->spl_object == null) {
- $this->spl_object = new SplFileObject($this->csv_file, 'rb');
- }
- return true;
- }
- public function get_data($length = 0, $start = 0) {
- if(!$this->_open_file()) {
- return false;
- }
- $length = $length ? $length : $this->get_lines();
- $start = $start - 1;
- $start = ($start < 0) ? 0 : $start;
- $data = array();
- $this->spl_object->seek($start);
- while ($length-- && !$this->spl_object->eof()) {
- $data[] = $this->spl_object->fgetcsv();
- $this->spl_object->next();
- }
- return $data;
- }
- public function get_lines() {
- if(!$this->_open_file()) {
- return false;
- }
- $this->spl_object->seek(filesize($this->csv_file));
- return $this->spl_object->key();
- }
- public function get_error() {
- return $this->error;
- }
- }
調用方法如下:
- include('CsvReader.class.php');
- $csv_file = 'path/bigfile.csv';
- $csvreader = new CsvReader($csv_file);
- $line_number = $csvreader->get_lines();
- $data = $csvreader->get_data(10);
- echo $line_number, chr(10);
- print_r($data);
其實,上述CsvReader類并不只針對CSV大文件,對于其他文本類型的大文件或超大文件同樣可用,前提是將類中fgetcsv方法稍加改動為current即可.
新聞熱點
疑難解答