За последние 24 часа нас посетил 76071 программист и 2969 роботов. Сейчас ищут 1516 программистов ...

Скрипт пошагового построчного чтения файла

Тема в разделе "Прочие вопросы по PHP", создана пользователем web_programmist, 27 авг 2009.

  1. web_programmist

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

    С нами с:
    20 июн 2009
    Сообщения:
    18
    Симпатии:
    0
    Есть ли у кого-нибудь скрипт пошагового построчного чтения файла, который например, сможет прочитать с 20й строчки - N колличество строк?
     
  2. Kreker

    Kreker Старожил

    С нами с:
    8 апр 2007
    Сообщения:
    5.433
    Симпатии:
    0
    Можно либо прочитать файл целиком и разбить по строкам на массив, либо читать от начала, определяя количество строк, а от нужной считать символы.
     
  3. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Код (PHP):
    1. <?php
    2. $file = file('file.txt');
    3. for ($i=19; $i<30; $i++)
    4. {
    5.      echo $file[$i];
    6. } 
     
  4. web_programmist

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

    С нами с:
    20 июн 2009
    Сообщения:
    18
    Симпатии:
    0
    Мне кажется что это ресурсоемкие операции в случае если текстовый файл большого размера. Поэтому хочется найти решение которое будет читать именно то что нужно (как писал выше). Поправьте если ошибаюсь по поводу ресурсов.
     
  5. Apple

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

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    Написал простенький класс, реализующий требуемый функционал:

    Код (PHP):
    1. <?php
    2.  
    3. final class FileReader
    4. {
    5.     protected $handler = null;
    6.     protected $fbuffer = "";
    7.     
    8.     
    9.     /**
    10.      * Конструктор класса, открывающий файл для работы
    11.      *
    12.      * @param string $filename
    13.      */
    14.     public function __construct($filename)
    15.     {
    16.         if(!($this->handler = fopen($filename, "rb")))
    17.             throw new Exception("Cannot open the file");
    18.     }
    19.     
    20.     
    21.     /**
    22.      * Построчное чтение всего файла с учетом сдвига
    23.      *
    24.      * @return string
    25.      */
    26.     public function ReadAll()
    27.     {
    28.         if(!$this->handler)
    29.             throw new Exception("Invalid file pointer");
    30.         
    31.         while(!feof($this->handler))
    32.             $this->fbuffer .= fgets($this->handler);
    33.         
    34.         return $this->fbuffer;
    35.     }
    36.     
    37.     
    38.     /**
    39.      * Установить строку, с которой производить чтение файла
    40.      *
    41.      * @param int  $line
    42.      */
    43.     public function SetOffset($line)
    44.     {
    45.         if(!$this->handler)
    46.             throw new Exception("Invalid file pointer");
    47.         
    48.         while(!feof($this->handler) && $line--) {
    49.             fgets($this->handler);
    50.         }
    51.     }
    52. };
    53.  
    54. /**
    55.  * Пример использования 
    56.  */
    57. $stream = new FileReader("lines.txt");
    58.  
    59. // Укажем, что читать надо с 20-ой строки
    60. $stream->SetOffset(20);
    61.  
    62. // Получаем содержимое
    63. $stream->ReadAll();
    64.  
    65. /**
    66.  * Количество прочитанных строк можно узнать так:
    67.  *
    68.  * echo count(explode("\n", $stream->ReadAll()));
    69.  */
    70.  
    71.  
    72. ?>
     
  6. Kreker

    Kreker Старожил

    С нами с:
    8 апр 2007
    Сообщения:
    5.433
    Симпатии:
    0
    Не ошибаетесь.

    Для начала ответьте на вопрос, что такое строка.
     
  7. Mat

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

    С нами с:
    12 дек 2006
    Сообщения:
    391
    Симпатии:
    0
    А цель какая приследуется? может XML задействовать проще?
     
  8. web_programmist

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

    С нами с:
    20 июн 2009
    Сообщения:
    18
    Симпатии:
    0
    Класс! Попробую сегодня.

    Все что содержится между началом строки и ее концом (символом перевода строки).

    Файл CSV, XML тут не подойдет.
     
  9. web_programmist

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

    С нами с:
    20 июн 2009
    Сообщения:
    18
    Симпатии:
    0
    Спасибо Apple, доработал - получилось то что нужно, гиговый файл в 2млн строк возвращает 5 строк начиная с 1млн - моментально!
    PHP:
    1. final class FileReader
    2. {
    3.     protected $handler = null;
    4.     protected $fbuffer = array();
    5.    
    6.     /**
    7.     * Конструктор класса, открывающий файл для работы
    8.     *
    9.     * @param string $filename
    10.     */
    11.     public function __construct($filename)
    12.     {
    13.         if(!($this->handler = fopen($filename, "rb")))
    14.             throw new Exception("Cannot open the file");
    15.     }
    16.    
    17.     /**
    18.     * Построчное чтение $count_line строк файла с учетом сдвига
    19.     *
    20.     * @param int  $count_line
    21.     *
    22.     * @return string
    23.     */
    24.     public function Read($count_line = 10)
    25.     {
    26.         if(!$this->handler)
    27.             throw new Exception("Invalid file pointer");
    28.        
    29.         while(!feof($this->handler))
    30.         {
    31.             $this->fbuffer[] = fgets($this->handler);
    32.             $count_line--;
    33.             if($count_line == 0) break;
    34.         }
    35.        
    36.         return $this->fbuffer;
    37.     }
    38.    
    39.    
    40.     /**
    41.     * Установить строку, с которой производить чтение файла
    42.     *
    43.     * @param int  $line
    44.     */
    45.     public function SetOffset($line = 0)
    46.     {
    47.         if(!$this->handler)
    48.             throw new Exception("Invalid file pointer");
    49.        
    50.         while(!feof($this->handler) && $line--) {
    51.             fgets($this->handler);
    52.         }
    53.     }
    54. };
    55.  
    56.  
    57. // Пример использования
    58.  
    59. $file = "file.txt";
    60. $line = 1000000;
    61. $count_line = 5;
    62.  
    63. $stream = new FileReader($file);
    64.  
    65. // Укажем, что читать надо с $line строки
    66. $stream->SetOffset($line);
    67.  
    68. // Получаем содержимое $count_line строк
    69. $result = $stream->Read($count_line);
    70.  
    71. print_r("<pre>");
    72. print_r($result);
    73. print_r("</pre>");
     
  10. Kreker

    Kreker Старожил

    С нами с:
    8 апр 2007
    Сообщения:
    5.433
    Симпатии:
    0
    Ну так -) Для нас символ перевода строки - это новая строка, для машины обычный символ. Машина не различает строки, мы не можем ей сказать "выбери с 4 по 6 строку".
    Нужно читать файл, считая строки, до тех пор, пока не будет достигнута последняя необходимая строка. Что и делает код, приведенный Apple. Работает он быстро от того, что прочтенные данные до момента "выборки" никуда не сохранятся и файл читается по частям, а не целиком.
     
  11. web_programmist

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

    С нами с:
    20 июн 2009
    Сообщения:
    18
    Симпатии:
    0
    Но скрипт обходит весь файл, хоть и быстро но обходит, ещё есть fseek, который перемещает указатель чтения, может с помощью него можно сделать скрипт побыстре, но пока у меня не получается. Что скажете насчет fseek?
     
  12. Kreker

    Kreker Старожил

    С нами с:
    8 апр 2007
    Сообщения:
    5.433
    Симпатии:
    0
    После "выборки" нужных строк - нет.

    Чтобы его использовать, нужно знать, куда смещать. Можно выбирать по 1000 символов и считать переводы строк, только это будет медленнее, чем во встроенной функции fgets.
     
  13. Apple

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

    С нами с:
    13 янв 2007
    Сообщения:
    4.984
    Симпатии:
    2
    Он сдвигает указатель на указанное количество байт.
    Вам известно, сколько байт каждая строка и равно ли их количество?
    Я полагаю, что нет.
     
  14. web_programmist

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

    С нами с:
    20 июн 2009
    Сообщения:
    18
    Симпатии:
    0
    да)) для этого я его и поставил, это его второе назначение)

    Правильно полагаешь.
     
  15. Driver86

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

    С нами с:
    27 апр 2008
    Сообщения:
    15
    Симпатии:
    0
    И всё было бы замечательно, если бы не мой случай))
    Дан файлик, в котором есть перевод строки, а есть символ экранирования (\) и сразу следующий за ним символ перевода строки. Как можно доработать класс, дабы он отличал перевод строки от экранированного перевода строки, который надо воспринимать как есть (как просто очередной символ и идти далее), а не как конец строки? хм....
     
  16. Simpliest

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

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Driver86
    проверяй последний прочитанный символ строки.
    Если \ значит не считай следующую за строчку и добавляй ее к текущей.
     
  17. Algernon

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

    С нами с:
    26 апр 2009
    Сообщения:
    9
    Симпатии:
    0
    посмотрите команду tail в *nix, елси вам последние строки надо читать. Еще есть готовая утилита ftptail (где-то в сети можно найти), написанная на перле - позволяет дергать последние н строк из файла, находящегося на удаленном сервере. По фтп)))
     
  18. AlexDev

    AlexDev Новичок

    С нами с:
    4 мар 2015
    Сообщения:
    3
    Симпатии:
    0
    Apple, спасибо, отличный класс
    а подскажи как сделать, чтобы можно было на получить определенные строки?
    допустим есть массив
    array('23242', '444', '2342', '777')
    и мне нужны именно эти строки из файла
    подскажите плиз
     
  19. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    Код (PHP):
    1. function getLinesById($filename, Array $ids) {
    2.   $out=array();
    3.   $cnt=1;
    4.   if ( ($fh = fopen($filename,'r')) !== false) {
    5.     $max = max($ids);
    6.     while ( ($line = fgets($fh)) !== false ) {
    7.       if (in_array($cnt,$ids)) {
    8.         $out[$cnt]=$line;
    9.       }
    10.       $cnt++;
    11.       if ($cnt>$max) break; //выходим, т.к. дальше нам строки ненужны
    12.     }//while
    13.     fclose($fh);
    14.   }
    15.   return $out;
    16. }
    17. echo '<pre>';
    18. print_r( getLinesById('test.php', array(7,16,1001) ) ); 
     
  20. AlexDev

    AlexDev Новичок

    С нами с:
    4 мар 2015
    Сообщения:
    3
    Симпатии:
    0
    спасибо большое
    а как выдать в массиве в том же формате как и на входе было?
    сейчас выдаются по возрастанию
     
  21. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    вместо
    $out = array();
    написать
    $out = array_combine($ids, array_fill(0,sizeof($ids),'') );
     
  22. AlexDev

    AlexDev Новичок

    С нами с:
    4 мар 2015
    Сообщения:
    3
    Симпатии:
    0
    Код (Text):
    1. array(53) {
    2.   [26400]=>
    3.   string(0) ""
    4.   [23044]=>
    5.   string(0) ""
    6.   [28199]=>
    7.   string(0) ""
    8.   [47969]=>
    9.   string(0) ""
    10.   [48254]=>
    11.   string(0) ""
    12.   [36139]=>
    13.   string(0) ""
    14.   [42957]=>
    15.   string(0) ""
    16.   [15682]=>
    17.   string(0) ""
    иногда не вытягивает данные
     
  23. runcore

    runcore Старожил

    С нами с:
    12 окт 2012
    Сообщения:
    3.625
    Симпатии:
    158
    пример файла. и подробности. невытягивает какието определенные номера, или ошибка повторяется только изредка?
     
  24. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Последнему сообщению в теме уже 6 лет. Он не подскажет.
     
  25. Zuldek

    Zuldek Старожил

    С нами с:
    13 май 2014
    Сообщения:
    2.381
    Симпатии:
    344
    Адрес:
    Лондон, Тисовая улица, дом 4, чулан под лестницей
    Последнюю функцию в циклах с большим количеством итераций я бы не советовал использовать.