чтение блока строк в файле с помощью php

Учитывая, что у меня есть текстовый файл объемом 100 ГБ, содержащий миллионы строк текста. Как я могу прочитать этот текстовый файл блоком строк с помощью PHP?

я не могу использовать file_get_contents();, потому что файл слишком большой. fgets() также читать текст построчно, что, вероятно, займет больше времени, чтобы закончить чтение всего файла.

Если я буду использовать fread($fp,5030), где '5030' - это некоторое значение длины, для которого он должен быть прочитан. Будет ли случай, когда он не будет читать всю строку (например, остановится в середине строки), потому что она достигла максимальной длины?


person ralpu    schedule 18.07.2011    source источник
comment
В чем именно вопрос? Есть ли ограничение на fread?   -  person MeLight    schedule 18.07.2011


Ответы (5)


я не могу использовать file_get_contents(); потому что файл слишком большой. fgets() также читает текст построчно, что, вероятно, займет больше времени, чтобы закончить чтение всего файла.

Не понимаю, почему нельзя использовать fgets()

$blocksize = 50; // in "number of lines"
while (!feof($fh)) {
  $lines = array();
  $count = 0;
  while (!feof($fh) && (++$count <= $blocksize)) {
    $lines[] = fgets($fh);
  }
  doSomethingWithLines($lines);
}

Чтение 100 ГБ в любом случае потребует времени.

person KingCrunch    schedule 18.07.2011
comment
Это может быть медленнее, чем подход fread, если строки очень короткие (множество отдельных небольших чтений требует больше накладных расходов на ввод-вывод, чем меньшее количество больших чтений). - person Oliver Charlesworth; 18.07.2011

Подход fread звучит как разумное решение. Вы можете определить, достигли ли вы конца строки, проверив, является ли последний символ в строке символом новой строки ('\n'). Если это не так, вы можете либо прочитать еще несколько символов и добавить их к существующей строке, либо вы можете обрезать символы из своей строки до последней новой строки, а затем использовать fseek для настройки своей позиции в файле.

Дополнительное замечание: знаете ли вы, что чтение файла размером 100 ГБ займет очень много времени?

person Oliver Charlesworth    schedule 18.07.2011

я думаю, что вы должны использовать fread($fp, somesize) и вручную проверять, нашли ли вы конец строки, иначе прочитайте другой фрагмент.

Надеюсь это поможет.

person wezzy    schedule 18.07.2011

Я бы порекомендовал реализовать чтение одной строки внутри функции, скрывая детали реализации этого конкретного шага от остального кода — обрабатывающая функция не должна заботиться о том, как была извлечена строка. Затем вы можете реализовать свою первую версию с помощью fgets(), а затем попробовать другие методы, если вы заметите, что она работает слишком медленно. Вполне может быть, что первоначальная реализация слишком медленная, но дело в том, что вы не узнаете, пока не проверите.

person soulmerge    schedule 18.07.2011

Я знаю, что это старый вопрос, но я думаю, что новый ответ будет полезен для всех, кто в конце концов найдет этот вопрос.

Я согласен с тем, что чтение 100 ГБ требует времени, поэтому я также согласен с тем, что нам нужно найти наиболее эффективный вариант чтения, чтобы его можно было как можно меньше, вместо того, чтобы просто думать: «Кого волнует, сколько это, если это уже много». "Итак, давайте узнаем наше самое низкое возможное время.

Другое решение:

Кэшировать часть необработанных данных

Используйте fread для чтения кеша этих данных

Читать построчно

Читать строку за строкой из кеша до конца кеша или конца найденных данных

Прочитайте следующий фрагмент и повторите

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

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

Чем больше размер кеша, тем быстрее вы читаете, но тем больше памяти вы используете.

person Nestor Mata Cuthbert    schedule 02.12.2016
comment
Я в той же лодке, что и @OP, ищу самый быстрый способ прочитать, в моем случае, 300 файлов, каждый по 5 ГБ, построчно. Я собираюсь провести большое количество тестов скорости с различными размерами, но мне интересно, что является хорошей отправной точкой для fread()? 1 КБ? 1 МБ? 1 ГБ? У моего сервера всего 4 ГБ оперативной памяти, так что, вероятно, это не тот гиг. Также, с другой стороны, объединение нескольких вставок в одну большую вставку для MySQL, что является хорошей отправной точкой для размера запроса INSERT? - person l008com; 01.06.2017
comment
Одна вещь, которую следует учитывать в отношении размера кеша, заключается в том, что если вы используете командную строку PHP или веб-PHP, если вы используете веб-PHP, вам нужно учитывать, что, возможно, этот же поток будет повторно использоваться, и если вы много увеличиваете использование памяти , это перетащит его на следующее повторное использование, и общее использование памяти останется высоким. - person Nestor Mata Cuthbert; 02.06.2017
comment
Что касается размера кеша в вашем случае, я бы сказал, что 1k — это очень мало, 1G — это определенно слишком много. Поскольку вы собираетесь проводить тесты, вы вполне можете протестировать несколько чисел, я бы посоветовал попробовать как минимум 512 КБ и, возможно, не более 1–4 МБ или что-то в этом роде. Просто хочу избегать чтения слишком часто, но вам не нужно избегать чтения вообще. Я бы сказал, что если вы можете прочитать от 100 до 1000 строк, то у вас все хорошо. ИМХО - person Nestor Mata Cuthbert; 02.06.2017