За последние 24 часа нас посетили 21698 программистов и 1016 роботов. Сейчас ищут 703 программиста ...

Большой файл и мало оперативки

Тема в разделе "PHP для профи", создана пользователем Nerfed, 18 июл 2018.

  1. Nerfed

    Nerfed Активный пользователь

    С нами с:
    21 июл 2017
    Сообщения:
    186
    Симпатии:
    12
    Есть список недействительных паспортов - файл в 1.5 Гб и есть задачка проверять по этому списку клиентов. Но на сервере оперативки всего 2 гига. То есть, через file_get_contents его не открыть. Какие тут есть варианты, кроме как парсить его на мощном компе на тысячи срок и записывать построчно в базу MySQL, которую потом переносить на сервер?
     
  2. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    читать кусками, никаких проблем
     
  3. Nerfed

    Nerfed Активный пользователь

    С нами с:
    21 июл 2017
    Сообщения:
    186
    Симпатии:
    12
    А как можно прочитать файл куском?
     
  4. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    кусочек за кусочком в цикле складываешь в буфер.
    из буфера читаешь номер, сравниваешь, пока буфет не станет такой маленький, что номера паспорта в нем не помещается
    читаешь следующую порцию данных, доклеиваешь в буфер
    и снова отрезаешь номер, сравниваешь и т.п.
     
  5. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.591
    Симпатии:
    360
    Подробности тут: fread()
     
    Nerfed нравится это.
  6. Nerfed

    Nerfed Активный пользователь

    С нами с:
    21 июл 2017
    Сообщения:
    186
    Симпатии:
    12
    Эм... это ничего не даст. Файл представляет из себя набор паспортных данных, которые идут построчно и поля разделены запятыми. Если fread разобьёт строку посередине серии паспорта например, то сверка с серией клиента не пройдёт. Вот был бы способ читать файл построчно...
    --- Добавлено ---
    Хотяяя... можно сохранять с предыдущим куском, склеивать с ним и проверять. То есть, получаем кусок 2, склеиваем с куском 1, получается разрыв между этими кусками убрали. Далее получаем кусок 3, склеиваем с куском 2, проверяем - разрыв между 2 и 3 тоже убрали. И так далее. Вроде правильная логика... Получается, каждый кусок будет проверяться по 2 раза, но зато без разрывов. Интересно даст ли это что-то в принципе, может скрипт так и съест 1.5 гига оперативки в процессе прогона цикла. Точнее, уже 3 гига, потому что я там собрался дублировать куски по 2 раза.
     
    #6 Nerfed, 18 июл 2018
    Последнее редактирование: 18 июл 2018
  7. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.822
    Симпатии:
    736
    Адрес:
    Татарстан
    К чему извращения? Загнал в мускульной и радуйся. Ели ж хочется прям извращений - прочел строку в буфер, сравнил, очистил буфер и так в цикле. Памяти мало съест, но скорость будет не ахти
     
  8. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    @Nerfed
    ты понимаешь, что на разовую проверку одного пасспорта придется прочесть и сравнить число со всеми данными в пасспорте?
    и так каждый раз

    пихай в бд, читая по-кусочкам. когда файл с новыми данными приходит - в бд его.

    а запросы уже все к бд.
     
    johovich нравится это.
  9. Abyss

    Abyss Старожил

    С нами с:
    12 дек 2015
    Сообщения:
    1.298
    Симпатии:
    218
    Адрес:
    Default city
    PHP:
    1. $fileHandler = fopen($file, "r");
    2. while($line = fgets($fileHandler)){
    3.     list($columnA, $columnB) = explode(",", $line);
    4.     // magic goes here
    5. }
    6. fclose($fileHandler);
     
    igordata нравится это.
  10. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    охуенно
     
  11. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    Еще недавно использовал такой классный трюк, когда надо читать большими кусками, но чтобы делилось построчно. Т.е. как бы "округлять" по строчкам. В твоем случае хорошо подойдет, потому что читать 1.5Гбайт построчно - долговато. Лучше читать кусками.

    Код (Text):
    1.  
    2. //тут размер куска
    3. $size = 4096;
    4. $bigfile = 'bigfile.txt';
    5. $h = fopen($bigfile, 'r');
    6. do {
    7.     $str = fread($h, $size) . fgets($h); //читаем заданный размер + 1 строку
    8. } while (!feof($h));
     
    igordata, artoodetoo и romach нравится это.
  12. Nerfed

    Nerfed Активный пользователь

    С нами с:
    21 июл 2017
    Сообщения:
    186
    Симпатии:
    12
    fopen выгружает файл в оперативку полностью же?
    Для построчного разбора есть ещё готовая функция: https://php.ru/manual/function.file.html

    Короче сделали по алгоритму, который я описывал выше. Работает шустро, сервер не греет. Такой скрипт идеально подойдёт, если в файле в принципе ничего не разбито на строки, а сравнить как-то надо.
    PHP:
    1. $size_open_file = 5000;
    2. $filesize = filesize($path);
    3. if ($filesize <= $size_open_file) {
    4.    $size_open_file = $filesize;
    5. }
    6. $handle = fopen($path, "r");
    7. $flag_search = 0;
    8. $contents_prev = "";
    9. do {
    10.    $contents = fread($handle, $size_open_file);
    11.    $contents_prev = $contents;
    12.    if (substr_count($contents_prev.$contents, $search_number)) {
    13.       $flag_search = 1;
    14.       break;
    15.    }
    16.    $filesize = $filesize - $size_open_file;
    17. } while ($filesize >= 0);
    18. fclose($handle);
    --- Добавлено ---
    Нам этот файл надо будет обновлять раз в неделю. Качать к себе, парсить в базу, заливать новую базу на сервер = слишком много телодвижений. А так, просто залил новый файл на сервер и доволен. Потом ещё сделаем автоматическое скачивание файла на сервер по ссылке раз в сутки. Для этого надо будет раздуплить как разархивировать 1.5 гиговый файл из архива gz2 и не уронить при этом сервер.
     
    #12 Nerfed, 20 июл 2018
    Последнее редактирование: 20 июл 2018
  13. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    Ты ничего не понял из тех дельных советов, что тебе надовали тут. :)

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

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

    Наверняка к моей писанине тоже можно ещё круче доебаться, но тут я не могу не сказать. :)
    Индусам платят за кодинг построчно, вот они так как у тебя пишут. $filesize = filesize()
     
  14. Abyss

    Abyss Старожил

    С нами с:
    12 дек 2015
    Сообщения:
    1.298
    Симпатии:
    218
    Адрес:
    Default city
    Вы видимо путаете что-то с file_get_contents.
    fopen создаёт поток из файла, управляют которым fread, fwite, fgets...
     
  15. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.591
    Симпатии:
    360
    Нет, просто предоставляет "указатель на файл", посредством которого другие функции (fread, fgets) выполняют над этим файлом свою работу...
    И ещё в приведённом в сообщении 12 коде надо 11-ю строчку перенести за 15-ю.
     
  16. acho

    acho Активный пользователь

    С нами с:
    28 дек 2016
    Сообщения:
    854
    Симпатии:
    210
    Адрес:
    Санкт-Петербург
    нет. Эта функция считывает весь файл и складывает его в массив.