Максимально быстрый способ перейти к нужной строке в gz файле

Тема в разделе "PHP", создана пользователем SoaringHawk, 25 сен 2009.

Статус темы:
Закрыта.
Модераторы: latteo
  1. SoaringHawk

    SoaringHawk Постоялец

    Регистр.:
    25 апр 2009
    Сообщения:
    61
    Симпатии:
    2
    Есть файл text.txt.gz. В нем много строк текста. Необходима быстрая выборка нужной строки, зная ее номер.
    Вариант "в лоб" просто перебирать каждую строку, пока не дойдешь до нужной:
    PHP:
    $gzf gzopen($имя_файла'r');
    for(
    $i 0$i <= $номер_нужной_строки$i++)
    {
         
    $ktxt gzgets($gzf4096);
    }
    gzclose($gzf);
    Но этот способ жутко медленный, когда строк за 1000 и нужно, например 999-ю. :) Дело в том, что не известны позиции новых строк, что бы использовать gzseek.
     
  2. Alternator

    Alternator

    Регистр.:
    23 мар 2009
    Сообщения:
    295
    Симпатии:
    145
    Перейти по ссылке
    думаю это будет работать быстрее
    но и памяти соответсвенно будет больше есть, по аналогии с file()
     
  3. SoaringHawk

    SoaringHawk Постоялец

    Регистр.:
    25 апр 2009
    Сообщения:
    61
    Симпатии:
    2
    Да ну. :D
    gzfile всегда читает весь файл + еще и массив создает. По моим тестам gzfile ~ в 1.26 раза медленнее, чем мой 1-й способ, при условии прохода по всем строкам. :)
     
  4. Alternator

    Alternator

    Регистр.:
    23 мар 2009
    Сообщения:
    295
    Симпатии:
    145
    провел набор тестов
    во первых, gzfile оказался на моих тестах чуточку быстрее
    во-чторых, я нашел альтернативный более быстрый способ(только его надо допилить напильником на предмет исключительных ситуаций)

    это код теста всех трех способов
    лучший -последний
    PHP:
    <?php
    //фыва

    $zp=gzopen('1.gz','w');
    for(
    $i=0;$i<10000;$i++)
        {
        for(
    $j=0,$s=rand(10,40);$j<$s;$j++)
            
    gzwrite($zp,chr(rand(0x30,0x39)));
        
    gzwrite($zp,"\r\n");
        }
    gzclose($zp);

    list(
    $msec,$sec)=explode(chr(32),microtime()); 
    $Begin_=$sec+$msec;
    //------------------------------------------------------------------------------------------
    for($i=0;$i<100;$i++)
        {
        
    $zp=gzopen('1.gz','r');
        for(
    $j 0$j <= 7000$j++)
            {
            
    $ktxt gzgets($zp4096);
            }
        
    gzclose($zp); 
        }
    echo 
    $ktxt.'<br>';
    //------------------------------------------------------------------------------------------
    list($msec,$sec)=explode(chr(32),microtime()); 
    $end_=$sec+$msec;
    echo 
    "<br>Скрипт выполнен за ".round($end_-$Begin_,4)." сек.<br>";
    //------------------------------------------------------------------------------------------
    list($msec,$sec)=explode(chr(32),microtime()); 
    $Begin_=$sec+$msec;
    //------------------------------------------------------------------------------------------
    for($i=0;$i<100;$i++)
        {
        
    $file=gzfile ('1.gz');
        
    $ktxt=$file[7000];
        }
    echo 
    $ktxt.'<br>';
    //------------------------------------------------------------------------------------------
    list($msec,$sec)=explode(chr(32),microtime()); 
    $end_=$sec+$msec;
    echo 
    "<br>Скрипт выполнен за ".round($end_-$Begin_,4)." сек.<br>";
    //------------------------------------------------------------------------------------------
    list($msec,$sec)=explode(chr(32),microtime()); 
    $Begin_=$sec+$msec;
    //------------------------------------------------------------------------------------------
    for($i=0;$i<100;$i++)
        {
        
    $zp=gzopen('1.gz','r');
        
    $buffer='';
        
    $counter=0;
        while(!
    gzeof($zp))
            {
            
    $buf=gzread($zp,100000);
            
    $temp_counter=substr_count($buf,"\r\n");
            
            
    //$buffer.=$buf;
            
    if($temp_counter+$counter>=7000)
                {
                
    $temp=explode("\r\n",$buf);
                
    $ktxt=$temp[7001-$temp_counter];
                break;
                }
            }
        
    gzclose($zp);
        
    //preg_match("/(?:.*\\r\\n){6999}(.*)/","dds",$matches);
        
    }
    echo 
    $ktxt.'<br>';
    //------------------------------------------------------------------------------------------
    list($msec,$sec)=explode(chr(32),microtime()); 
    $end_=$sec+$msec;
    echo 
    "<br>Скрипт выполнен за ".round($end_-$Begin_,4)." сек.<br>";
    ?>
    советую поигратся для последнего с размером буфера чтения
     
  5. SoaringHawk

    SoaringHawk Постоялец

    Регистр.:
    25 апр 2009
    Сообщения:
    61
    Симпатии:
    2
    Да, забавно. У тебя в примере gzfile быстрее и 3-й вариант работает практически вдвое быстрее первых двух. :)
    ... но, стоит увеличить длину строки хотя бы в 10 раз (строка 7, поставить к примеру rand(100,400)) и результаты поменяются в корне. А ведь у меня строки длиной не менее 1000. Хотя даже в этом случае 3-й вариант чуток, но быстрее. :)
    И как видно gzfile проигрывает вчистую.
     
  6. Alternator

    Alternator

    Регистр.:
    23 мар 2009
    Сообщения:
    295
    Симпатии:
    145
    а где об этом изначально у тебя было написано?
    тестировал на тех цифрах, что пришли в голову.
    раз, третий все равно быстрее, попробуй провести тест с ним, для разных значений буфера
    думаю, можно добиться более высокой производительности
     
Статус темы:
Закрыта.