Разбор больших текстовых файлов с PHP без убийства сервера

Я пытаюсь прочитать некоторые большие текстовые файлы (между 50M-200M), делая простую замену текста (по сути, xml, который у меня не был правильно экранирован в нескольких обычных случаях). Вот упрощенная версия функции:

<?php function cleanFile($file1, $file2) { $input_file = fopen($file1, "r"); $output_file = fopen($file2, "w"); while (!feof($input_file)) { $buffer = trim(fgets($input_file, 4096)); if (substr($buffer,0, 6) == '<text>' AND substr($buffer,0, 15) != '<text><![CDATA[') { $buffer = str_replace('<text>', '<text><![CDATA[', $buffer); $buffer = str_replace('</text>', ']]></text>', $buffer); } fputs($output_file, $buffer . "\n"); } fclose($input_file); fclose($output_file); } ?> 

То, что я не получаю, это то, что для самых больших файлов, около 150 Мбайт, использование памяти PHP выходит из графика (около 2 ГБ) до сбоя. Я подумал, что это самый эффективный способ запоминания больших файлов. Есть ли какой-то метод, который мне не хватает, что будет более эффективным для памяти? Возможно, некоторые настройки, которые хранят вещи в памяти, когда их собирать?

Другими словами, он не работает, и я не знаю, почему, и насколько я знаю, я неправильно делаю что-то. Любое направление для меня? Спасибо за любой вклад.

Solutions Collecting From Web of "Разбор больших текстовых файлов с PHP без убийства сервера"

PHP для этого не предназначен. Разгрузите работу в другой процесс и вызовите ее или запустите ее с PHP. Я предлагаю использовать Python или Perl .

Из моего скудного понимания сборки мусора PHP следующее может помочь:

  1. unset $buffer когда вы закончите записывать его на диск, явно указывая GC, чтобы очистить его.
  2. поместите блок if в другую функцию, поэтому GC запускается, когда эта функция завершается.

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

Я ожидаю, что во многих случаях это провалится. Вы читаете куски 4096 байт. Кто знает, что отсечка не будет в середине <text> ? В этом случае ваша str_replace не будет работать.

Вы считали, что используете регулярное выражение?