2015-09-04 26 views
3

假設我需要從CSV文件中的第50行到第100行的所有數據。 我想知道是否有更有效的方式循環遍歷每一行並檢查當前行是否在50到100之間? 現在我有一個簡單的代碼工作正常,但如果我想要一個範圍接近CSV文件的結尾,那麼它會變得有點慢。使用PHP獲取部分CSV文件的有效方法

$start = 200000; 
$end = 200050; 
$handle = fopen("test.csv", "r"); 
$i = 0; 
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { 
if(($start <= $i) && ($i <= $end)) { 
    echo $data[0] . ' - ' . $data[1] . ' - ' . $data[2] . ' - ' . $data[3]; 
    echo '<br />'; 
} 
elseif($i > $end) { 
    break; 
} 
$i++; 
} 

fclose($handle); 

有沒有辦法使用偏移量或類似的東西,所以我不必循環每一行?

更新: 該解決方案需要處理較大的文件。內存有限,因此將整個文件讀入內存將不起作用。

+0

問題:一旦您加載了CSV數據,您打算如何處理這些CSV數據?我問,因爲加載CSV數據的最常見原因是將其保存到數據庫中。如果這就是你正在做的事情,並且你正在使用MySQL,那麼你可以使用'LOAD DATA INFILE'查詢來讓MySQL直接加載CSV數據,而不需要PHP來完成任何工作。這對你來說會少很多,而且執行速度會很快。 – Simba

+0

基本上是CRUD操作。我必須使用CSV。在這種情況下數據庫不是一個選項。 – gtsongi

+0

數據庫不是一個選項嗎?哇。甚至不是SQLite或NoSQL引擎之一?您希望這裏有多少數據,因爲即使您解決了內存問題,如果您不允許進行任何索引編制,您的性能也會非常糟糕。 – Simba

回答

0

你可以使用:

$filename = "data.csv"; 

// Read the file into an array 
$lines = file($filename); 

// Output the 50th line 
echo $lines[49]; 

所以,使用例如,你可以輕鬆地輸出的50線,你需要使用:

for($i=0; $i<50; $i++) { 
    echo $lines[$i + 50] . '<br/>; 
} 

檢查出PHP的file函數的文檔

+0

謝謝,但這意味着我必須將整個文件讀入內存,這在遇到較大文件時會遇到問題。對不起,我忘了將這些信息添加到我的帖子中。我會更新它。 – gtsongi

+0

在這種情況下,完全是一個完全不同的問題。你可以用'''fseek'''來指定偏移量,但是你需要通過總字節大小來知道。如果每條線的長度完全相同,這可以很容易地計算出來。 – Amo

-1
for($i=49; $i<100;$i++) { 
    echo $lines[$i].PHP_EOL; 
} 
+0

爲什麼OP應該這樣做?一個好的答案將總是解釋做了什麼以及爲什麼這樣做,不僅是爲了OP,而且是爲了將來SO的訪問者。 –

0

以下代碼將逐行讀取大文件

<?php  
    function readLine ($linenum,$fh) { 
       $line = fgets ($fh, 4096); 
       $pos = -1; 
       $i = 0; 

       while (!feof($fh) && $i<($linenum-1)) { 
        $char = fgetc($fh); 
        if ($char != "\n" && $char != "\r") { 
         fseek($fh, $pos, SEEK_SET); 
         $pos ++; 
        } 
        else $i ++; 
       } 
       $line = fgets($fh); 
       return $line; 
      } //readLine() 
    ?> 
0

好了,你已經有了一個CSV數據文件,可能含有大量的記錄,你需要能夠潛入到做直接從進一步下跌的文件讀取,而不需要讀取休息第一個文件。

是的,這是可以做到 - 你將需要使用fseek()移動文件位置指針:

$handle = fopen(....); 
.... 
$startAt = 10000; 
$success = fseek($handle, $startAt); 
$data = fgets($fp, 1000); //read the next 1000 bytes of the file after the starting position. 

然而,這不會是容易的,你作爲例子使它看起來。

您的CSV數據幾乎肯定具有可變長度的行。這意味着你不能只是告訴它跳轉到一個特定的字節位置,並知道它是哪一行。您必須有一種方法來知道要跳轉到的記錄的特定起始字節位置。如果有任何記錄被編輯,那麼以前記住的那些字節位置將會變得不正確。

如果您只是使用這種分頁方式,那麼您可以通過記住前一頁的字節位置並根據當前位置+1來計算下一頁的開始。

但是,跳到文件周圍的任意記錄(例如隨機訪問,給定記錄編號)幾乎是不可能的,除非您保留所有行結束符所在字節位置的最新索引。 (如果你這樣做,那麼你將有效地實現一個基本的ISAM數據庫)

真正的問題是爲什麼(根據您的評論)數據庫是不可能的。好吧,也許你不能安裝mySQL,但是一個簡單的SQLite數據庫可以完全由你的PHP程序創建和管理,並且只在磁盤上創建一個文件;在這方面,它幾乎和CSV一樣方便,如果你的數據量不是很多,肯定會更容易。