Перейти из форума на сайт.

НовостиФайловые архивы
ПоискАктивные темыТоп лист
ПравилаКто в on-line?
Вход Забыли пароль? Первый раз на этом сайте? Регистрация
Компьютерный форум Ru.Board » Интернет » Web-программирование » PHP: Скрипт для удаления одинаковых строк из файла
работает нормально, но когда файл в котором более 80к сток..

Модерирует : Cheery

 Версия для печати • ПодписатьсяДобавить в закладки
Страницы: 1 2

Открыть новую тему     Написать ответ в эту тему

DJCosmos



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Есть скрипт для удаления одинаковых сток из файла:

Код:
 
<?php  
 
//удаляет из файла file.txt все одинаковые строки
set_time_limit(0);  
$file="file.txt";  
$infa=file("$file");  
echo count($infa),"<br>";  
$_file=file($file);  
$_file=array_values(array_unique($_file));  
 
$fp=fopen($file,"w+");  
for($i=0;$i<count($_file);$i++)  
{  
flush();  
fputs($fp,$_file[$i]);  
}  
 
echo "Unique strings =",$i,"<br>";  
echo "done<br>"; flush();  
fclose($fp);  
 
?>
 

работает нормально, но когда файл в котором примерно более 80к сток, выдаёт ошибку:
 
Fatal error: Allowed memory size of 20971520 bytes exhausted (tried to allocate 66 bytes) in  /home/.............................../clear.php on line 8
 
Подскажите как решить проблему?

Всего записей: 55 | Зарегистр. 12-06-2004 | Отправлено: 18:35 10-09-2006
Brodyaga



Silver Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
Тебе позволено только некоторое количество информации загрузить в память.
Не считывай сразу весь файл, а построчно.Памяти так тратится меньше.

----------
Damn Metal

Всего записей: 2713 | Зарегистр. 07-01-2006 | Отправлено: 20:48 10-09-2006
DJCosmos



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Brodyaga
А подскажи как это написать? я не очень силён в PHP

Всего записей: 55 | Зарегистр. 12-06-2004 | Отправлено: 21:20 10-09-2006
Cheery



.:МордератоР:.
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
DJCosmos

Цитата:
А подскажи как это написать? я не очень силён в PHP

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

----------
Away/DND

Всего записей: 52737 | Зарегистр. 04-04-2002 | Отправлено: 21:26 10-09-2006
N Sensey N



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Cheery
Не очень понял как ты объяснил алгоритм.. я бы сделал так:
 
Читаем первую строку и записываем ее в новый файл...
Читаем вторую строку - и проверяем нет ли этой строки в новом файле.. если нету - дописываем в новый файл.... если есть - не пишем...
Берем третью строку и проверяем нет ли ее в новом файле... если нету - дописываем в новый файл... есть есть - не пишем...
 
Ну и та далее...
 
Хотя наверное ты это и имел ввиду =))

----------
sPaiz-Nuke - Free PHP CMS Web Design and Development Портал для израильтян

Всего записей: 1409 | Зарегистр. 01-10-2002 | Отправлено: 23:11 10-09-2006
Cheery



.:МордератоР:.
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
N Sensey N

Цитата:
Хотя наверное ты это и имел ввиду =))

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

----------
Away/DND

Всего записей: 52737 | Зарегистр. 04-04-2002 | Отправлено: 23:22 10-09-2006
cwll



Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Алгоритм в 3 строчки:
 
1. Загоняем строки в массив  
2. Удаляем не уникальные  
3. Сохраняем массив
 

Цитата:
 
<?php  
$arr1= file ('mix.txt');
$result = array_unique($arr1);
 
for ($i=0; $i<count($result); $i++)
{$text .= $result[$i] ;}
 
$out=fopen('out.txt','w');
fwrite($out,"$text");
fclose($out);
?>
 

 
Курим бамбук или что покрепче...
 
Можно join - тогда еще короче будет.

----------
Друзья: заправка картриджей ремонт копиров ремонт мобильных телефонов

Всего записей: 206 | Зарегистр. 26-10-2005 | Отправлено: 09:51 11-09-2006 | Исправлено: cwll, 09:58 11-09-2006
batva



crazy administrator
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
cwll
Как же ты строки загонишь в массив если памяти нехватает?
 
Прежде чем отвечать, ты хотя бы вопрос до конца дочитай..

Всего записей: 12593 | Зарегистр. 07-01-2001 | Отправлено: 09:56 11-09-2006
sket4



Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
я бы заюзал нечто вроде system('cat ... | uniq');
там, в принципе, все равно какое количество строк

Всего записей: 712 | Зарегистр. 07-05-2004 | Отправлено: 10:25 11-09-2006
CheRt



Advanced Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
Так как ПХП плохо знаю предлагаю алгоритмические решения:
 
1. Создаем хэш, его и каждую строку вешаем ключен, а значение инкрементируем. $strings{$this_string}++
Таким образом получаем уникальные строки и количество каждой.
 
2. Дерево. Берем n строчек файла(допустим первые 5000), ищем уникалы, сохраняем во временный, далее следующие n и т.д., после завершение цикла обрабатываем первым методом временный файл.

----------
В огне бода нет и не будет!
До встречи в СССР 2.0!

Всего записей: 1118 | Зарегистр. 14-12-2001 | Отправлено: 10:33 11-09-2006 | Исправлено: CheRt, 10:34 11-09-2006
afiget



Full Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
batva
Прежде чем отвечать ты сначала вчитайся в приведенный код и найди отличия :).
Я вот тоже не понял автора топика, зачем фактически создавать еще 1 массив в памяти через array_values?
sket4
Здается мне, что сервер у автора чужой, т.е. наемный. Следовательно - врядли.

Всего записей: 545 | Зарегистр. 31-12-2005 | Отправлено: 10:41 11-09-2006
Kokoc

Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Еще можно создать БД mysql с 1 полем и уникальным индексом.
Текст построчно запихнуть в БД (строки-дубликаты не войдут), потом обратно.

Всего записей: 793 | Зарегистр. 06-06-2002 | Отправлено: 11:05 11-09-2006
DaVasyaDa

Newbie
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
N Sensey N
Решение хорошее, спору нет. Только есть мнение, что при таких ограничениях есть и ограничение на время выполнения самого скрипта. Посему, как вариант, это все реализовать на си или на perl (на си предпочтительнее), тем самым добиваясь сокращения времени выполнения в несколько раз.
 
set_time_limit(0) - решение не особо хорошее, после висения скрипта n минут погонят с хостинга, к гадалке не ходи (это если настройки сервера вообще позволят выполнить такой канделябр).
 
P.S. хотя как таковой объем не известен, но для файлов содержащих более 5000 (прим.) строк, php  вообще не выход.

Всего записей: 29 | Зарегистр. 27-07-2006 | Отправлено: 11:38 11-09-2006
batva



crazy administrator
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
afiget

Цитата:
Прежде чем отвечать ты сначала вчитайся в приведенный код и найди отличия .  

 

 
Kokoc

Цитата:
Еще можно создать БД mysql  

А если нет доступа к серверу БД?
Как вариант, можно создать пустой хеш, связать его с db файлом, и все.. будет очень быстро и красиво. )
Наверно это самый оптимальный вариант, чтобы не ломать мозги.
 
А вообще задача интересная.
Может быть из исходного файла сделать отсортированный? А потом уже легко убить дубли? Но тогда выходной файл будет также отсортирован, оно нам надо?
 
 
Давайте предложим каждый по варианту, а потом посмотрим чей будет быстрее?
 
Задача.
Скриптом на PHP или Perl убить повторяющиеся строки в большом файле.
 
Условия.
Не использовать системные команды.
Не использовать базы данных включая Berkeley DB и прочие.
Не использовать память всмысле использовать по минимуму.

Всего записей: 12593 | Зарегистр. 07-01-2001 | Отправлено: 11:46 11-09-2006
edogs

Advanced Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
batva
Скажем только один нюанс.
Мы вот недавно когда отлаживали скрипты, подметили интересную особенность.
код вида

Код:
 
for($i=0;$i<=10000;$i++) $a=file_get_contents('a.txt');
 

сдыхает от недостатка памяти как описано выше... файл a.txt - всего 1Кб.
И количество кушаемой памяти зависит от количества проходов по циклу.
Имхо у пхп отвратительно настроена "мусорка", поэтому не факт что задача имеет решение.
Возможно может помочь shmop, если он включен...

Всего записей: 1778 | Зарегистр. 25-07-2004 | Отправлено: 14:38 11-09-2006
Brodyaga



Silver Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору

Код:
 
<?php
ini_set("memory_limit","0M");
$num_parts=20;
$filename="new.txt";
$fsize=filesize($filename);
$part=ceil($fsize/$num_parts);
$sum=0;
for($i=0;$i<=$num_parts-1;$i++){
$parts[$i]=$part;
$sum+=$part;
}
$lastpart=$fsize-($sum-$part);
$parts[$num_parts-1]=$lastpart;
$fpm=fopen($filename,"r");
$fpa=fopen("$filename.tmp","w");
foreach($parts as $k=>$v){
$from=array_sum(array_slice($parts,0,$k));
$to=$from+$v;
fseek($fpm,$from);
$fp=fopen("$filename$k","w");
fwrite($fp,fread($fpm,$v));
fwrite($fpa,join("",array_unique(file("$filename$k"))));
fclose($fp);
unlink("$filename$k");
}
fclose($fpa);
$fpa=fopen("$filename.new","w");
fwrite($fpa,join("",array_unique(file("$filename.tmp"))));
fclose($fpa);
unlink($filename.".tmp");
?>
 

Тестировался на файле с 400000 записями, 12 с лишним мегабайт.
На скорую руку, основная идея разрезание файла.
Однозначно что он кривоват(2 цикла это слишком), но пока в голову лезет всякая чушь
 
Добавлено:
Кстати, файл 400000 записей я заполнил md5 хешами случайных чисел от 1 до 2000, и что интересно, 12 мегабайтный файл без повторений стал размером 65 кб
Вот тебе и псевдослучайность

----------
Damn Metal

Всего записей: 2713 | Зарегистр. 07-01-2006 | Отправлено: 14:38 11-09-2006 | Исправлено: Brodyaga, 14:43 11-09-2006
DJCosmos



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Brodyaga
Тестил твой скрипт, вроде нормально работает.
Но например берём файл new.txt, удаляем в нём дубликаты, получается файл new.txt.new
переименовываем файл new.txt.new в new.txt и снова проверяем его на дубликаты и почему-то получаем фал размером чуточку больше чем  изначально полученный new.txt.new
повторяем процедуру и получаем файлик ещё чуточку больше, как такое может получаться?

Всего записей: 55 | Зарегистр. 12-06-2004 | Отправлено: 15:32 11-09-2006
Brodyaga



Silver Member
Редактировать | Профиль | Сообщение | ICQ | Цитировать | Сообщить модератору
А на какую чуточку?
Может быть просто внизу добавляются строки пустые?
Потому что у меня не меняется размер, или совсем не заметно...щас посмотрю на пустые строки...

----------
Damn Metal

Всего записей: 2713 | Зарегистр. 07-01-2006 | Отправлено: 16:08 11-09-2006
DJCosmos



Junior Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Brodyaga
 
Ну вот например:
исходный файл = 5 013 547 байт
после удаления дубликатов = 4 620 837 байт
повторяем операцию получаем файл = 4 767 335 байт
повторяем операцию получаем файл = 5 013 547 байт
 
В файлах добавляется больше пустых строк между урлами, как это исправить?
 

Всего записей: 55 | Зарегистр. 12-06-2004 | Отправлено: 19:04 11-09-2006
Cheery



.:МордератоР:.
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору
Brodyaga
к чему такие сложности?  

Код:
<?php
  $fw=fopen('out.txt','w');
  $fr=fopen('test.txt','r');
  while (!feof($fr))  
   {
    $str = fgets($fr, 4096);
    $curpos=ftell($fr);
    if (check_string($str,$fr)) {fseek($fr,$curpos);continue;}
      else {fseek($fr,$curpos);fwrite($fw,$str);}    
   }
   fclose($fr);
   fclose($fw);
function check_string($str,$fp)
{
  while (!feof($fp))  
   {
    $strf = fgets($fp, 4096);
    if ($strf==$str) return true;    
   }
  return false;
}
?>

ед, что вроде зацикливается где то после обработки..щас гляну
ну да, на границе..

----------
Away/DND

Всего записей: 52737 | Зарегистр. 04-04-2002 | Отправлено: 19:34 11-09-2006 | Исправлено: Cheery, 19:38 11-09-2006
Открыть новую тему     Написать ответ в эту тему

Страницы: 1 2

Компьютерный форум Ru.Board » Интернет » Web-программирование » PHP: Скрипт для удаления одинаковых строк из файла


Реклама на форуме Ru.Board.

Powered by Ikonboard "v2.1.7b" © 2000 Ikonboard.com
Modified by Ru.B0ard
© Ru.B0ard 2000-2025

LiteCoin: LgY72v35StJhV2xbt8CpxbQ9gFY6jwZ67r

Рейтинг.ru