2010-07-03 2 views
10

Я читаю файл, содержащий около 50 тыс. Строк, используя функцию file() в Php. Тем не менее, это дает ошибку из памяти, так как содержимое файла хранится в памяти в виде массива. Есть ли другой путь?Наименее интенсивный способ чтения файла в PHP

Кроме того, длина сохраненных строк является переменной.

Вот код. Также файл 700kB не mB.

private static function readScoreFile($scoreFile) 
{ 
    $file = file($scoreFile); 
    $relations = array(); 

    for($i = 1; $i < count($file); $i++) 
    { 
     $relation = explode("\t",trim($file[$i])); 
     $relation = array(
         'pwId_1' => $relation[0], 
         'pwId_2' => $relation[1], 
         'score' => $relation[2], 
         ); 
     if($relation['score'] > 0) 
     { 
      $relations[] = $relation; 
     } 
    } 

    unset($file); 
    return $relations; 
} 
+0

Я знаю, этот вопрос старый, но две вещи здесь. 1. читать файл по строкам. 2. Ошибка вне памяти может заключаться в том, что вы также храните все в массиве, как правило, это не очень хорошая идея без какого-либо контроля и знания памяти у вас есть – Atherion

ответ

13

Использование fopen, fread и fclose читать файл последовательно:

$handle = fopen($filename, 'r'); 
if ($handle) { 
    while (!feof($handle)) { 
     echo fread($handle, 8192); 
    } 
    fclose($handle); 
} 
+0

, это не работает, я хочу читать строки за строкой.Его возвращающие mutliple строки на каждом fread (я думаю, 8192 байта) – Chetan

+7

заменить fread на «fgets»: fgets - Получает строку из указателя файла –

+0

Вы можете использовать промежуточную переменную $ line для хранения байтов каждой строки, а затем echo $ line , fread, вероятно, является одним из наиболее эффективных способов потока файла, поэтому прочитайте результаты fread (и добавьте в строку $), пока не найдете разрыв строки. Затем сделайте все, что хотите, с этой строкой, затем установите $ line = "" и возобновите добавление результатов fread в строку $. – luiscubal

9

EDIT после обновления вопрос comments to answer of fabjoa:

Существует, безусловно, что-то подозрительное, если через 700kb файл съедает до 140 МБ памяти с этим кодом, который вы дали (вы могли бы unset $ отношения в конце каждой итерации). Подумайте об использовании отладчика, чтобы пройти через него, чтобы узнать, что произойдет. Вы могли бы также рассмотреть вопрос о перезаписи коды для использования SplFileObject's CSV functions а (or their procedural cousins)

SplFileObject::setCsvControl example

$file = new SplFileObject("data.csv"); 
$file->setFlags(SplFileObject::READ_CSV); 
$file->setCsvControl('|'); 
foreach ($file as $row) { 
    list ($fruit, $quantity) = $row; 
    // Do something with values 
} 

Для объектно-ориентированного подхода к итерации по файлу, попробуйте SplFileObject:

SplFileObject::fgets example

$file = new SplFileObject("file.txt"); 
while (!$file->eof()) { 
    echo $file->fgets(); 
} 

SplFileObject::next example

// Read through file line by line 
$file = new SplFileObject("misc.txt"); 
while (!$file->eof()) { 
    echo $file->current(); 
    $file->next(); 
} 

или даже

foreach(new SplFileObject("misc.txt") as $line) { 
    echo $line; 
} 

Довольно много связанных (если не дублировать):

+0

Я думаю, что это все еще может потенциально использовать большой кусок памяти, поскольку я думаю, что он продолжает читать, пока не найдет конец строки. – Artefacto

+0

, как и выше, я хочу читать строки за строкой (завершается \ n) – Chetan

+0

@Artefacto, вы все равно можете использовать 'SplFileObject :: setMaxLineLen', если это проблема. – Gordon

0

выделить больше памяти во время операции, может быть что-то как в i_set ('memory_limit', '16M') ;. Не забудьте вернуться к первоначальному распределению памяти после завершения операции

+0

Я уверен, что после операции вам не нужно сбросить ограничение памяти, оно применимо только к текущему запущенному сценарию. –

+0

Я уже использую 140 МБ памяти (из чтения файла много чего-то происходит) – Chetan

+1

@Cettan это звучит подозрительно для меня. 50 тыс. Строк не так много. [Библия короля Джеймса] (http://www.gutenberg.org/etext/26361) имеет около 20 тыс. Строк, составляет 1 МБ в виде простого текста и занимает примерно ~ 3 МБ при чтении с помощью файла(). Каков общий размер в байтах вашего файла? – Gordon

1

Если вы не знаете максимальную длину линии, и вам не удобно использовать магическое число для максимальной длины линии, тогда вам нужно будет выполнить начальное сканирование файла и определить максимальную длину строки.

Кроме этого следующий код должен помочь вам:

// length is a large number or calculated from an initial file scan 
    while (!feof($handle)) { 
     $buffer = fgets($handle, $length); 
     echo $buffer; 
    } 
Смежные вопросы