Мне нужно было получать строку из файла по порядковому номеру. То есть первую, десятую, 390815-ую, и т.д. Сначала мне хватало цикла fgets, который прокручивал до нужной строки. На строке 500000 такой способ у меня занимал уже почти минуту, что явно плохо. Stream_get_line был совем не быстрее, а даже медленнее процентов на 30.
Первый из костылей, пришедших мне в голову был fseek до значения в 500000 строк (посчитал байты), а оттуда уже крутил fgets. Но так как у меня идет обработка до 100 тысяч строк в сутки, то через пару дней опять пришлось высчитывать смещение для fseek. Опять же, требовался другой выход. И я его таки нашел.
function getFileLine($file, $line) { return trim(exec("head -n $line $file | tail -n 1")); }
Head берет N первых строк файла, tail N последних. Все гениальное просто. 1 миллионная строка берется из файла за 1.027 сек, 40 миллионная - 30 секунд, что очевидно быстрее прокручивания fgets. (Конечно, если не прыгать fseek до 40 миллионной записи и считывать 40000001-ую)
Конечно, решение ограничено *nix системами, но т.к. моя система и без того использует pcntl_fork, она уже была привязана к никсам, так что хуже мне не стало.
А еще я писал про:










Январь 11th, 2010 at 17:03
Всемогущий Си!
Январь 11th, 2010 at 17:08
Да и вообще, использовать возможности платформы на которой все работает бывает полезно;)
Январь 11th, 2010 at 17:18
А нечего такие объемы в файлах хранить
Январь 12th, 2010 at 09:23
А как насчет производительности?
Январь 12th, 2010 at 13:14
Нагрузка процессора упала с 99% до 0-30%
По времени 0,5-1 сек на чтение для меня в данном случае приемлемо.
Февраль 7th, 2010 at 11:07
Решение конечно есть, но! есть крейзи-хостеры которые под виндой запускают пых и если ты просто арендуешь хостинг, тебе врятли дадут доступ к командной строке…
Февраль 7th, 2010 at 11:17
Ну если вам надо обрабатывать файлы в сотни тысяч строк, полагаю, что рублей 250 в месяц на ВДС собрать можно.
Ну а на хостерах да, такие трюки, скорее всего, не пройдут. Делайте fseek, крутите оттуда циклом fgets, каждые N итераций расчитывайте и запоминайте новую позицию для fseek.
Февраль 16th, 2010 at 02:07
Сомнительное решение
Попробуйте выполнить
sed ’40000000q;d’ filename
И напишите сюда время выборки.
Февраль 16th, 2010 at 12:56
white:/home/1# time sed ’40000000q;d’ file.lst
PUMPING4LIFE
real 5m38.109s
user 2m1.152s
sys 0m2.560s
white:/home/1# time head -n 40000000 file.lst | tail -n 1
PUMPING4LIFE
real 0m46.676s
user 0m7.320s
sys 0m5.480s
Нет, ваш способ не прокатывает.
Февраль 16th, 2010 at 20:57
Спасибо, удивили, всегда седом пользовался, правда не на таких больших файлах.