Как сэкономить память при чтении файла в Php? - PullRequest
7 голосов
/ 09 апреля 2010

У меня есть файл размером 200 КБ, который я использую на нескольких страницах, но на каждой странице мне нужно только 1-2 строки этого файла, так как я могу читать только эти строки, что мне нужно, если я знаю номер строки?

Например, если мне нужна только 10-я строка, я не хочу загружать в память все строки, только 10-ю строку.

Извините за мой плохой английский!

Ответы [ 7 ]

19 голосов
/ 09 апреля 2010

Попробуйте SplFileObject

echo memory_get_usage(), PHP_EOL;        // 333200

$file = new SplFileObject('bible.txt');  // 996kb
$file->seek(5000);                       // jump to line 5000 (zero-based)
echo $file->current(), PHP_EOL;          // output current line 

echo memory_get_usage(), PHP_EOL;        // 342984 vs 3319864 when using file()

Для вывода текущей строки вы можете использовать current() или просто echo $file. Я считаю, что более понятным является использование этого метода. Вы также можете использовать fgets(), но это приведет к следующей строке.

Конечно, вам нужны только средние три строки. Я добавил вызовы memory_get_usage только для того, чтобы доказать, что этот подход почти не потребляет памяти.

3 голосов
/ 09 апреля 2010

Если вы не знаете смещение линии, вам нужно будет прочитать каждую строку до этой точки. Вы можете просто выбросить старые строки (которые вам не нужны), просматривая файл с чем-то вроде fgets(). (РЕДАКТИРОВАТЬ: вместо fgets(), я бы предложил @ Гордон решение )

Возможно, лучшим решением было бы использование базы данных, поскольку ядро ​​базы данных выполнит основную работу по сохранению строк и позволит вам (очень эффективно) получить определенную "строку" (это не будет строка, но запись с числовым идентификатором, однако это равносильно тому, что вам не нужно читать записи перед ней.

2 голосов
/ 09 апреля 2010

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

 $offsets = array();
 while ($line = fread($filehandle)) { .... find line 10 .... }
 $offsets[10] = ftell($filehandle); // store line 10's location
 .... find next line
 $offsets[20] = ftell($filehandle);

и так далее. После этого вы можете легко перейти к расположению этой линии следующим образом:

 $fh = fopen('file.txt', 'rb');
 fseek($fh, $offsets[20]); // jump to line 20

Но это может быть излишним. Попробуйте сравнительный анализ операций - сравните, сколько времени занимает старомодное «чтение 20 строк» ​​с предварительным вычислением / переходом.

1 голос
/ 09 апреля 2010
<?php
    $lines = array(1, 2, 10);

    $handle = @fopen("/tmp/inputfile.txt", "r");
    if ($handle) {
        $i = 0;
        while (!feof($handle)) { 
            $line = stream_get_line($handle, 1000000, "\n");

            if (in_array($i, $lines)) {
                echo $line;
                            $line = ''; // Don't forget to clean the buffer!
            }

            if ($i > end($lines)) {
                break;
            }

            $i++;
        } 
        fclose($handle);
    }
?>
0 голосов
/ 09 апреля 2010

Почему вы пытаетесь загрузить только первые десять строк? Знаете ли вы, что загрузка всех этих строк на самом деле является проблемой?

Если вы не измеряли, значит, вы не знаете, что это проблема. Не тратьте свое время на оптимизацию без проблем. Скорее всего, любое изменение производительности, если вы не загрузите весь файл размером 200 КБ, будет незаметным, если только вы точно не знаете, что загрузка этого файла является узким местом.

0 голосов
/ 09 апреля 2010

использовать fgets () . 10 раз :-) в этом случае вы не будете хранить все 10 строк в памяти

0 голосов
/ 09 апреля 2010

Просто переберите их без сохранения, например,

$i = 1;
$file = fopen('file.txt', 'r');
while (!feof($file)) {
   $line = fgets($file); // this gets whole line from the file;
   if ($i == 10) {
       break; // break on tenth line
   } 
   $i ++;
}

В приведенном выше примере память будет сохраняться только для последней строки, полученной из файла, поэтому это наиболее эффективный способ памяти.

...