2010-05-26 8 views
1

매우 큰 CSV 파일이 있습니다. 정확히 51427 라인.PHP에서 큰 CSV 파일 읽기

필요한 줄만 배열로 읽을 수있는 방법이 없습니까? 그러면 속도가 크게 빨라질 것입니다.

+1

당신은'ini_set ("max_execution_time", 0)'처럼 최대 실행 시간을 가지고 놀았습니까? – robjmills

+0

몇 가지 질문 : - 어떻게 파일을 데이터베이스로 가져 오시겠습니까? - 가져 오기 전에 파일을 업로드 하시겠습니까? 아니면 실시간으로 읽으십니까? – allnightgrocery

답변

2

csv 파일을 스트리밍하는 것이 좋습니다. ProgressiveReader.php

class NoFileFoundException extends Exception { 
    function __toString() { 
     return '<h1><b>ERROR:</b> could not find (' 
        .$this->getMessage(). 
        ') please check your settings.</h1>'; 
    } 
} 

class NoFileOpenException extends Exception { 
    function __toString() { 
     return '<h1><b>ERROR:</b> could not open (' 
        .$this->getMessage(). 
        ') please check your settings.</h1>'; 
    } 
} 

interface Reader { 
    function setFileName($fName); 
    function open(); 
    function setBufferOffset($offset); 
    function bufferSize(); 
    function isOffset(); 
    function setPacketSize($size); 
    function read(); 
    function isEOF(); 
    function close(); 
    function readAll(); 
} 

class ProgressiveReader implements Reader { 
    private $fName; 
    private $fileHandler; 
    private $offset = 0; 
    private $packetSize = 0; 

    public function setFileName($fName) { 
     $this->fName = $fName; 
     if(!file_exists($this->fName)) { 
      throw new NoFileFoundException($this->fName); 
     } 
    } 

    public function open() { 
     try { 
      $this->fileHandler = fopen($this->fName, 'rb'); 
     } 
     catch (Exception $e) { 
      throw new NoFileOpenException($this->fName); 
     } 
     fseek($this->fileHandler, $this->offset); 
    } 

    public function setBufferOffset($offset) { 
     $this->offset = $offset; 
    } 

    public function bufferSize() { 
     return filesize($this->fName) - (($this->offset > 0) ? ($this->offset + 1) : 0); 
    } 

    public function isOffset() { 
     if($this->offset === 0) { 
      return false; 
     } 
     return true; 
    } 

    public function setPacketSize($size) { 
     $this->packetSize = $size; 
    } 

    public function read() { 
     return fread($this->fileHandler, $this->packetSize); 
    } 

    public function isEOF() { 
     return feof($this->fileHandler); 
    } 

    public function close() { 
     if($this->fileHandler) { 
      fclose($this->fileHandler); 
     } 
    } 

    public function readAll() { 
     return fread($this->fileHandler, filesize($this->fName)); 
    } 
} 

에 paramters를 얻을 수로 읽기 시작 위치와 바이트 수를 시작 파일 위치를 보내기 여기에 단위 테스트는 다음과 같습니다

require_once 'PHPUnit/Framework.php'; 

require_once dirname(__FILE__).'/../ProgressiveReader.php'; 

class ProgressiveReaderTest extends PHPUnit_Framework_TestCase { 

    protected $reader; 
    private $fp; 
    private $fname = "Test.txt"; 

    protected function setUp() { 
     $this->createTestFile(); 
     $this->reader = new ProgressiveReader(); 
    } 

    protected function tearDown() { 
     $this->reader->close(); 
    } 

    public function test_isValidFile() { 
     $this->reader->setFileName($this->fname); 
    } 

    public function test_isNotValidFile() { 
     try { 
      $this->reader->setFileName("nothing.tada"); 
     } 
     catch (Exception $e) { 
      return; 
     } 

     $this->fail(); 
    } 

    public function test_isFileOpen() { 
     $this->reader->setFileName($this->fname); 
     $this->reader->open(); 
    } 

    public function test_couldNotOpenFile() { 
     $this->reader->setFileName($this->fname); 
     try { 
      $this->deleteTestFile(); 
      $this->reader->open(); 
     } 
     catch (Exception $e) { 
      return; 
     } 

     $this->fail(); 
    } 

    public function test_bufferSizeZeroOffset() { 
     $this->reader->setFileName($this->fname); 
     $this->reader->open(); 
     $this->assertEquals($this->reader->bufferSize(), 12); 
    } 

    public function test_bufferSizeTwoOffset() { 
     $this->reader->setFileName($this->fname); 
     $this->reader->setBufferOffset(2); 
     $this->reader->open(); 
     $this->assertEquals($this->reader->bufferSize(), 9); 
    } 

    public function test_readBuffer() { 
     $this->reader->setFileName($this->fname); 
     $this->reader->setBufferOffset(0); 
     $this->reader->setPacketSize(1); 
     $this->reader->open(); 
     $this->assertEquals($this->reader->read(), "T"); 
    } 

    public function test_readBufferWithOffset() { 
     $this->reader->setFileName($this->fname); 
     $this->reader->setBufferOffset(2); 
     $this->reader->setPacketSize(1); 
     $this->reader->open(); 
     $this->assertEquals($this->reader->read(), "S"); 
    } 

    public function test_readSuccesive() { 
     $this->reader->setFileName($this->fname); 
     $this->reader->setBufferOffset(0); 
     $this->reader->setPacketSize(6); 
     $this->reader->open(); 
     $this->assertEquals($this->reader->read(), "TEST1\n"); 
     $this->assertEquals($this->reader->read(), "TEST2\n"); 
    } 

    public function test_readEntireBuffer() { 
     $this->reader->setFileName($this->fname); 
     $this->reader->open(); 
     $this->assertEquals($this->reader->readAll(), "TEST1\nTEST2\n"); 
    } 

    public function test_isNotEOF() { 
     $this->reader->setFileName($this->fname); 
     $this->reader->setBufferOffset(2); 
     $this->reader->setPacketSize(1); 
     $this->reader->open(); 
     $this->assertFalse($this->reader->isEOF()); 
    } 

    public function test_isEOF() { 
     $this->reader->setFileName($this->fname); 
     $this->reader->setBufferOffset(0); 
     $this->reader->setPacketSize(15); 
     $this->reader->open(); 
     $this->reader->read(); 
     $this->assertTrue($this->reader->isEOF()); 
    } 

    public function test_isOffset() { 
     $this->reader->setFileName($this->fname); 
     $this->reader->setBufferOffset(2); 
     $this->assertTrue($this->reader->isOffset()); 
    } 

    public function test_isNotOffset() { 
     $this->reader->setFileName($this->fname); 
     $this->assertFalse($this->reader->isOffset()); 
    } 

    private function createTestFile() { 
     $this->fp = fopen($this->fname, "wb"); 
     fwrite($this->fp, "TEST1\n"); 
     fwrite($this->fp, "TEST2\n"); 
     flush(); 
     fclose($this->fp); 
    } 

    private function deleteTestFile() { 
     if(file_exists($this->fname)) { 
      unlink($this->fname); 
     } 

    } 
} 
+1

한 번 (또는 드문) 가져 오기 프로세스 가능성이있는 코드를위한 코드입니다. csv를 업로드하고 mysql 콘솔을 사용하여 데이터를로드하십시오. – racerror

+0

옳은 말입니다. 그는 전체 파일이 업로드 될 때까지 기다리기를 원하지 않는다는 것을 제외하고는 * '처리하기 전에 배열로 CSV 파일의 전체 51427 줄에 도달해야하는 것이 행복하지 않습니다.'*. 또한 코드에 대한 몇 가지 테스트가 있습니다. 오, 한 사람 ** ** 한 번 ** 당신이 화나게하고 자동화 할 때까지 또 다른 노력이 중복됩니다. – Gutzofter

2

데이터베이스 서버에 직접 연결할 수 있습니까?

그렇다면 SQLyog와 같은 타사 프로그램을 사용하여 CSV 파일을 가져 오는 것이 좋습니다.

또한 파일을 업로드하고 직접 데이터를 가져 오기 위해 MySQL의 쉘을 사용할 수

LOAD DATA INFILE '/path/to/your_file.csv' INTO TABLE table_name FIELDS TERMINATED BY ','; 
1

스크립트는 아마도 너무 오래 걸립니다과 종료됩니다.

php.ini에서 max_execution_time 지시어를 찾아서 원하는대로 설정해야합니다.

기본 max_execution_time은 30 초로 설정되어 있으므로 스크립트가 종료 될 수 있습니다.

제한된 시간이 필요한 스크립트가있는 경우 set_time_init();

1

bash/shell (Linux를 사용하는 경우)을 사용하여 csv를 mysql으로 가져 왔습니까? 루비 나 펄이나 기타 등등을 사용할 수도 있습니다. 필자가 php (또는 웹 응용 프로그램) 대신 파일을 가져와야한다고 생각합니다.

2

이 배열

50000 개 + 라인의 모든으로 전체 CSV 파일을 읽고?

PHP에서 파일의 원하는 블록을 시작하여 한 행 (fgets())을 읽은 다음 각 (필요한) 행을 배열에 추가합니다. fgetcsv()를 사용하여 행의 배열을 가져올 수 있습니다.

편집 : 정확한 세부 사항을 모르지만 데이터 구조에 모든 것을 읽는 것이 우리가 필요로하는 것만을 읽는 것보다 더 많은 것을 느낍니다. 나는 빠른 MySQL의 LOAD 데이터 INFILE 명령을 사용하여 제안

0

바하마을! 이 대답을 무시하십시오. 중복되었습니다. 위의 fgetcsv()에 대한 Scorchio의 언급을 보라.