CITKIT.ru
3 терабайта свободного софта!
Logo    
IT-рынок Новости мира IT Океан(!) софта на CITKIT.ru Форумы Поступления в библиотеку Учебный центр Курилка
CitForum    CITForum на CD Море(!) аналитической информации! :: CITFORUM.RU
IT-консалтинг Software Engineering Программирование Open Source СУБД Безопасность Internet Сети Операционные системы Hardware

16.05.2005

Google
WWW CITForum.ru

Новости мира IT:

  • 11.05 - Intel создает свою группу по Open Source
  • 11.05 - Банк контролирует использование USB устройств при помощи DeviceLock
  • 11.05 - Microsoft устранила опасную дыру в Windows
  • 11.05 - "Корпорация ОСС" создает антимонопольный альянс операторов IP-телефонии
  • 11.05 - В Mac OS X найдены множественные уязвимости
  • 11.05 - "Билайн" запускает услугу "Мобильная почта"
  • 11.05 - Две критические уязвимости в браузере Firefox 1.0.3
  • 11.05 - IBM покупает начинающую Open Source-компанию Gluecode
  • 11.05 - Microsoft готова к битве с Open Source за школы
  • 11.05 - Sun завершит "открытие" Solaris в ближайшие 45 дней
  • 11.05 - Создатели браузера Firefox выпускают юбилейные монеты в честь 50 миллионов скачанных копий
  • 11.05 - Вышла пятая версия мобильной ОС от Microsoft
  • 11.05 - Поисковые движки умнеют быстрее, чем люди
  • 11.05 - Фишеры постоянно совершенствуются
  • 11.05 - Специалисты прогнозируют появление аналога Google Adsense от "Яндекс"
  • 06.05 - ICANN озаботилась проблемой торговых марок
  • 06.05 - Google патентует сортировку новостей
  • 06.05 - Intel готовит двуядерные процессоры второго поколения
  • 06.05 - Schoolforge-UK и OSC продвигают Open Source в школы
  • 06.05 - Новая версия рекламной программы подстрекает пользователей купить ПО для своего лечения
  • 06.05 - Microsoft продает ряд своих закрытых разработок
  • 06.05 - Google Labs анонсировал ускоритель интернета
  • 06.05 - Microsoft подвешивает пиратам "морковку"
  • 06.05 - В США входят в обиход "интеллектуальные" тележки для супермаркетов
  • 06.05 - Microsoft работает над аналогом PDF
  • 05.05 - Yahoo video search теперь доступен массам
  • 05.05 - Алмазы помогут бороться с хакерами
  • 05.05 - Интернет-охоту хотят запретить
  • 05.05 - Microsoft привлекает блоггеров для теста Longhorn
  • 05.05 - Основатель Red Hat предложил Стиву Джобсу помощь в решении проблемы с торговой маркой
  • 05.05 - Компьютерная система оргкомитета Кубка мира по футболу 2006 года пострадала от червя Sober
  • 04.05 - Cisco Systems представила многофункциональный продукт Adaptive Security Appliance 5500
  • 04.05 - Администрация Евросоюза поддержала идею всеевропейской интернет-библиотеки
  • 04.05 - Компьютерный вирус дарит билеты на чемпионат мира по футболу
  • 04.05 - Лаборатория Касперского: Обзор вирусной активности - апрель 2005
  • 04.05 - Microsoft хочет отсудить у россиянина два домена
  • 04.05 - Сделка между Lenovo и IBM завершена
  • 04.05 - Эпидемия червя Sober.p зафиксирована в Западной Европе
  • 04.05 - Panda Software публикует отчет о вирусной активности за апрель
  • 03.05 - Институт SANS обновил список наиболее опасных уязвимостей

    Архив новостей >>>


  • 2005 г.

    Обход дерева каталогов с прерыванием и возобновлением или "Куда мы идем завтра?"

    Паша Звягинцев, «Королевство Delphi»

    Программист,
    просыпаясь утром с сильнейшего похмелья,
    начинает с тестирования памяти...

    Недавно занимаясь интересной задачкой по написанию службы индексации, столкнулся с интересным вопросом: " А как бы нам поиск заморозить и продолжить после (через минуту, завтра, через месяц)?". Да конечно можно сказать - что у тебя за машина такая, вот у меня дерево каталогов обходит за 3 минуты... Согласен, это не вопрос. Но когда нужно не просто обходить, а еще и выполнять некоторые действия с файлами, да если их на диске 150 тыс. и больше, да еще не загружая процессор на 100%, то время может затянуться до нескольких суток, вот тогда - как быть?

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

    Со стандартной процедурой обхода дерева сталкивались очень многие

    procedure FileFind(path:string);
      var sr:Tsearchrec;// Описываем структуру, которую
                        //  использует для поиска система
      found:integer; // найдено или нет
    begin
      found:=FindFirst(path + '\*.*', FaAnyfile, sr);
        {по команде FindFirst программа создает
        структуру следующего типа
        TsearchRec = record
         Time: Integer; // время создания
         Size: Integer; // его размер
         Attr: Integer;// атрибуты
         Name:TFileName // = TString; собственно имя файла
         ExcludeAttr: Integer; найденные атрибуты
         FindHandle: THandle; // !!! указатель на структуру
         //поиска, которую создает система, а не наша программа.
         //Вот для чего обязательно в конце поиска
         //указывать FindClose -   это высвобождает память
         FindData: TWin32FindData; // собственно эта структура
    	end;}
      while (found = 0) do // если хоть что-то найдено
       begin
        if (sr.name <> '.') and (sr.name <> '..') then
        begin // если это не указатели на корневые каталоги,
              // то что-то нашли
          if (sr.attr and FaDirectory) = FaDirectory then
            // ага вот поддиректория - вызываем себя рекурсивно,
            // но с поиском уже
            // в этой директории
            FileFind(path+'\'+sr.name)
            else
            begin
              // вот тут выполняем чтото с найденным файлом
              //......
              mainform.memo1.lines.append(path+'\'+sr.name);
            end
          end;
       found:=findnext(sr); // есть ли еще файлы или каталоги
       end;
       FindClose(sr); // поиск закончен - нужно освободить память
    end;
    

    Казалось бы сохранить состояние процедуры поиска просто - достаточно сохранить структуру - sr:TsearchRec, а потом ее восстановить и поиск продолжится.

    Первое
    Однако при даже невнимательном рассмотрении процедуры видно, что она вызывает сама себя - налицо обычная рекурсия. Получается что надо сохранять не одну SearchRec, а несколько. Полдела - сохранить, но ведь нужно и восстановить эти рекурсивные вызовы. Т.е при продолжении поиска построить этакую матрешку из процедур поиска, а потом уже его продолжать.
    Второе
    — сама SearchRec. Казалось бы она находится в области данных нашей программы. Да это наполовину верно. Верхняя половина SearchRec действительно лежит в области данных нашей программы и делать мы с ней можем что душе угодно. Это переменные Time: Integer; Size: Integer; Attr: Integer; Name:TFileName; ExcludeAttr: Integer;. А вот вторая ее половина (FindHandle: THandle; FindData: TWin32FindData;) нам не принадлежит -ее генерирует система по нашему запросу FindFirst(.....) и уничтожает по команде FindClose(....).
    Третий,
    казалось бы, простой вопрос — SearchRec.Name имеет тип TFileName=TString. Какую длину он имеет? Одни скажут 255, другие 65535. Согласен, и то и другое верно, но не тут. Длина действительно 255. А вот с типом нас нагло обманули. Реально в памяти хранится не TString [255], а PChar {Имя файла}+PChar{его расширение}. Для нас с вами это преобразуется в обычную строку при обращении, и до столкновения с данной ситуацией я свято верил что там TString[255].Кстати в чем разница между Богом и билом гейтсом? Бог не считает себя билом гейтсом ...

    И так попробуем решить эти проблемы. Проше всего разбор начать в обратном порядке... (не подумайте превратно, я знаю через что рвут гланды в России...)

    Третий вопрос - как сохранить , а потом восстановить SearchRec, если он состоит непонятно из чего. А давайте сделаем свой SearchRec, как нам нужно. А именно так

    type // этот тип почти полностью переписывается 
         // со стандартного TSearchRec
     TMysearchRec = record
       Time: Integer;
       Size: Integer;
       Attr: Integer;
       Name: string[250];//вот тут обрабатывалось неверно
                           при типе TString, как длина ?
       ExcludeAttr: Integer;
       FindHandle: THandle;  // в принципе не нужен, но
                             // не будем сильно пугать читателей
                             // сильными отличиями, да и бог
                             // с ними - с восемью байтами
       FindData: TWin32FindData;
     end;
    

    но нам еще требуется сохранять несколько переменных самой программы, а именно Found - найдено чтото или нет и Path - с каким параметром нас вызывали, поэтому на основе этого типа делаем еще один

    TMyRec_Sea = record
       Rec_Sea:TMySearchRec; // наша структура поиска
       path:String[250]; // откуда начинали
       found:integer; // при остановке нашли чтото или нет
    end;
    

    Второй вопрос после первого решается не очень красиво, но довольно легко. Да система генерит структуру: FindHandle: THandle; FindData: TWin32FindData. FindData - собственно сама структура и FindHandle - указатель на нее. Пусть система генерит что угодно, если с умом, то можно обойти и это. Многие ли помнят такое INT21h->INT 13H. Думаю вспомнили. При восстановлении поиска дадим команду FindFirst, а потом подменим FindData и остальные поля, не трогая FindHandle, иначе сразу после окончания поиска (!!! ???) получим обращение к недопустимому адресу и вылет программы.

    ......
        // создаем запись для поиска
        FindFirst(path+'\'+mask, FaAnyfile, sr);
        delfile:=false; found:=buffer.found;
        // загоняем в SEARCHREC все кроме FINDHANDLE
        // (он создается системой)
        sr.Time:=buffer.rec_sea.Time;
        sr.Size:=buffer.rec_sea.Size;
        sr.Attr:=buffer.rec_sea.Attr;
        sr.Name:=buffer.rec_sea.Name;
        sr.ExcludeAttr:=buffer.rec_sea.ExcludeAttr;
        sr.FindData:=buffer.rec_sea.FindData;
    

    Первый вопрос - как же сохранять состояние процедуры при рекурсии?. Давайте сохранять SearchRec в файл и используем принцип магазина (не продуктового, а от автомата калашникова) - последний вошел - первый вышел. Вот примерная структура процедуры при выполняющемся поиске ( при нескольких рекурсивных вызовах)

    Findfile('c:\')
        Findfile('c:\Docs')
            FindFile(c:\Docs\Delphi')
               ......
    

    При получении сигнала на остановку процедуры начинают писать в файл в обратном порядке, а именно - FindFile(c:\Docs\Delphi'),Findfile('c:\Docs'),Findfile('c:\'). Примерно так

    Findfile('c:\')------------------------------------+
        Findfile('c:\Docs')---------------------+      !
            FindFile(c:\Docs\Delphi') ---+      !      !
                                         v      v      v
           [файл сохранений состояния] [rec1] [rec2] [rec3]
    

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

    Да, едва не забыл, как мы узнаем что надо приостановить поиск ? Давайте заведем глобальную переменную Process. Как она станет False - пора останавливаться

    Ниже приведена часть модуля с использованием описанных алгоритмов

    Unit unit1;
    ......
    var
    ....
      process:boolean; // вот глобальная переменная
                       // она и управляет поиском
                       // true - можно
                       // false - стоп с запоминанием состояния
    .....
    
    procedure FileFind(path:string;resume:boolean);
    { сканирует диск (вернее дерево каталогов)
    при вызове PATH - начальный каталог
    для обхода
    RESUME - если TRUE - то продолжать сохраненный поиск
    (тогда значение PATH игнорируется, кроме случая,
    когда не обнаружен файл
    сохранения поиска)
    при установке глобальной переменной PROCESS в
    false останавливается
    с запоминанием предыдущего состояния,
    внимание - РЕКУРСИЯ !!! }
    const
       save_ext='.rec'; // в каталоге приложения
                        //создает SAVE файл с именем
                        //приложения и указанным расширением
       mask='*.*';
    type
       TMysearchRec = record
        //пришлось написать свой тип SEARCHREC
        //с NAME фиксированной длины
         Time: Integer; Size: Integer; Attr: Integer;
         Name: string[250];	//вот тут обрабатывалось
                            // неверно при типе TString,
                            // как длина ?
         ExcludeAttr: Integer;  FindHandle: THandle;
         FindData: TWin32FindData;
       end;
       TMyRec_Sea = record
           Rec_Sea:TMySearchRec;
           path:String[250];  found:integer;  delfile:boolean;
       end;
    var
      sr:TSearchRec;
      RecFile:TFileStream;
      buffer:tMyRec_Sea;
      sp,save_file_name:string; found:integer; delfile:Boolean;
      delfile:Boolean;
    begin
      if resume then
      // возобновить поиск или начать новый
      begin
            save_file_name:=ChangeFileExt(ParamStr(0),save_ext);
            if FileExists(save_file_name) then
            begin
               RecFile:=TFileStream.Create(save_file_name,
                                           fmOpenReadWrite);
               // чистим буфер, не важно, необходимо для отладки
               fillchar(buffer,sizeof(buffer),#0);
               // читаем сохранение начиная с конца файла
               RecFile.Seek(-1*sizeof(buffer),soFromEnd);
               RecFile.Readbuffer(buffer,sizeof(buffer));
               path:=buffer.path; sp:=path;
               // создаем запись для поиска
               FindFirst(path+'\'+mask, FaAnyfile, sr);
               delfile:=false; found:=buffer.found;
               // загоняем в SEARCHREC все кроме FINDHANDLE
                  (он создается системой)
               sr.Time:=buffer.rec_sea.Time;
               sr.Size:=buffer.rec_sea.Size;
               sr.Attr:=buffer.rec_sea.Attr;
               sr.Name:=buffer.rec_sea.Name;
               sr.ExcludeAttr:=buffer.rec_sea.ExcludeAttr;
               sr.FindData:=buffer.rec_sea.FindData;
               // режем кусок уже прочитали свои данные - другим
               // они не понадобятся
               RecFile.Seek(-1*sizeof(buffer),soFromEnd);
               recfile.Size:=RecFile.Position;
               // дорезались - дозагружаться неоткуда
               if RecFile.Size=0 then delfile:=true;
               RecFile.Free;
               if delfile then sysutils.DeleteFile(save_file_name);
            end
            else
            // нет сохраненных поисков
            begin
               // начинаем новый
               sp:=path;  resume:=false;
               // тут исправляется разница между C:\ и
               // C:\DOCS - убираем
               // последний слэш
               if sp[length(sp)]='\'
               then  sp:=copy(sp,1,length(sp)-1);
               found:=FindFirst(sp + '\'+mask, FaAnyfile, sr);
            end
      end
      else
      begin
         // новый поиск - пристрелить старые записи
         save_file_name:=ChangeFileExt(ParamStr(0),save_ext);
         if fileExists(save_file_name)
         then sysutils.DeleteFile(save_file_name) ;
         sp:=path;
         if sp[length(sp)]='\' then  sp:=copy(sp,1,length(sp)-1);
         found:=FindFirst(sp + '\'+mask, FaAnyfile, sr);
      end;
      // закончена подготовка - вперед поиск
      while (found = 0) and process do
      begin
        application.ProcessMessages;
        if (sr.name <> '.') and (sr.name <> '..') then
        begin
           if (sr.attr and FaDirectory) = FaDirectory
              then
              begin
                 FileFind(sp+'\'+sr.name,resume);
              end
              else
              begin
                // ну тут разные действия с найденым файлом
                mainform.label1.caption:=
                ('начат разбор  '+sp+'\'+sr.name) ;
                // ................
                // закончили действия
    
                Application.ProcessMessages; // а вот без этого
                 // мы никогда не узнаем что пора поиск закончить
              end;
        end;
        if process then found:=findnext(sr);
      end;
      if not process then
        // получили сигнал на остановку сканирования
           нужно запомнить состояние
        begin
            save_file_name:=ChangeFileExt(ParamStr(0),save_ext);
            if not FileExists(save_file_name) then
                RecFile:=TFileStream.Create(save_file_name,fmCreate)
              else RecFile:=TFileStream.Create(save_file_name,
                            fmOpenReadWrite);
            RecFile.Seek(0,soFromEnd);
            // заполняем буфер текущим состоянием
            buffer.rec_sea.Time :=sr.Time;
            buffer.rec_sea.Size :=sr.Size ;
            buffer.rec_sea.Attr :=sr.Attr ;
            buffer.rec_sea.Name :=sr.Name ;
            buffer.rec_sea.ExcludeAttr :=sr.ExcludeAttr ;
            buffer.rec_sea.FindHandle :=sr.FindHandle ;
            buffer.rec_sea.FindData :=sr.FindData ;
            buffer.path:=sp; buffer.found:=found;
            RecFile.Writebuffer(buffer,sizeof(buffer));
            RecFile.Free;
        end;
      Application.ProcessMessages;
      sysutils.FindClose(sr);
    end;
    


     


    ХАЙВЕЙ - лучший российский хостинг-провайдер: хостинг, регистрация доменов, услуга Ваша@почта, поддержка 24 часа


    NetPromoter - единственный российский профессиональный комплекс программ и сервисов для раскрутки сайта и интернет-статистики


    STSS - известный поставщик надежных серверных решений различного назначения на платформе Intel (Xeon) и AMD.


    5-55: the ITIL company. Практический опыт и теоретические знания на лучших семинарах по ITIL и процессам ITSM.


    Подписка на новости IT-портала CITForum.ru
    (библиотека, ftp-архив CITKIT.ru)

    Новые поступления в on-line библиотеку:

    28 апреля

  • Выбор первого дистрибутива Linux: Пособие для начинающих
  • Обфускация и защита программных продуктов
  • Анализ и оптимизация циклов с помощью производящих функций
  • Стратегии объектно-реляционного отображения: систематизация и анализ на основе паттернов

    26 апреля

  • Business Intelligence обещает значительный рост в 2005 году
  • Десять основных тенденций 2005 года в области Business Intelligence и Хранилищ данных
  • Управление эффективностью бизнеса и предсказуемость
  • Увеличение эффективности бизнеса: пять ошибок управления, которых следует избегать
  • Потребность в организационных данных: модель комплексного управления эффективностью бизнеса
  • Технология Хранилищ данных для государственных учреждений
  • Оцените, насколько совершенно ваше Хранилище данных

    21 апреля

  • Исполнение моделей при помощи виртуальной машины
  • Параллельные алгоритмы компьютерной алгебры
  • От стандарта до стандарта (о стандартизации оптических разъемов)
  • За штурвалом IP-станции

    Продолжение дискуссии читателей:

  • Линукс и пользователи, или что мне не нравится в Linux
  • Еще один взгляд на альтернативные ОС (и софт для них)
  • О некомпетентности пользователя Windows
  • Переписка Долгачева В.С. и Монахова В.В.

    19 апреля

  • Межпротокольный шлюз NAT-PT с функциями DNS-ALG и FTP-ALG для обеспечения взаимодействия между сетями IPv4 и IPv6
  • Рефакторинг архитектуры программного обеспечения: выделение слоев
  • Комбинаторика слов и построение тестовых последовательностей
  • Функциональное тестирование Web-приложений на основе технологии UniTesK

    14 апреля

  • Как организовать двойную парольную защиту данных в Oracle
  • Деревянный интерфейс

    Продолжение дискуссии читателей:

  • Microsoft против мира
  • Впечатления от прочитанного

    12 апреля

  • Крупные проблемы и текущие задачи исследований в области баз данных
  • Глава 2 из книги Т.Кайта "Oracle для профессионалов"Архитектура

    Дискуссия читателей о Linux и Windows:

  • Деньги правят миром, и у кого их больше, тот и прав!
  • О злокозненности некомпетентных пользователей, или почему я не люблю ограниченных пользователей Windows

    7 апреля

  • О доблести Билла Гейтса, или почему Windows лучше, чем LINUX или Mac OS
  • Витая пара - все ли так просто?!
  • Выбираем сервер печати
  • Один слой хорошо, а два - лучше (о пишущих DVD-приводах)

    5 апреля

  • Использование Caché SQL Gateway
  • Глава 19 из книги Т.Кайта "Oracle для профессионалов"Хранимые процедуры на языке Java
  • Что такое PostgreSQL?
  • Обновлен PostgreSQL FAQ

    31 марта

  • Использование Веб-сервисов в Caché
  • Защита на уровне строк (Oracle)
  • Секции в реальном мире

    29 марта

  • Разработка успешных приложений для Oracle - первая глава из книги Тома Кайта "Oracle для профессионалов"
  • Web-сервисы: растущие опасения (мнение аналитиков IDC)
  • Технология OLAP - мощная альтернатива электронным таблицам
  • Какой модной стала подготовка отчетности

    24 марта

  • Многоверсионность данных и управление параллельными транзакциями
  • Исключение из правил. Опыт разработки и внедрения финансовой корпоративной системы
  • Обнаружение компрометаций ядра Linux с помощью gdb
  • Корпоративная сервисная шина - "бюджетный" подход к решению задач интеграции
  • Сервис-ориентированная архитектура
  • Бизнес-процессы и XML

    22 марта

  • Доступно. И точка! (обзор точек беспроводного доступа)
  • Коммутаторы Fast/Gigabit Ethernet для "большой" сети
  • Push to Talk: нажми на кнопку и ...говори
  • Сети нового поколения и технология softswitch

    17 марта

  • Часто задаваемые вопросы о proxy (proxy FAQ)
  • Самонастраивающаяся база данных: управляемые приложения и настройка SQL
  • Еще раз о волоконных трассах
  • Настраиваем русский Unicode в FreeBSD-5.3.

    10 марта

  • Еще не сказанное о волоконной оптике
  • Wi-Fi на службе оператора
  • Пора менять платформу?
    (о сокетах LGA775 и PGA478)

    Oracle:

  • Детальный аудит для практических целей
  • Шифруем свои ресурсы данных

    3 марта

  • Требования к проекту. Классификация - первый шаг к пониманию
  • Gtk vs. Qt: драки не будет
  • Управление бизнесом "по максимуму": BPM для финансовых учреждений
  • Реализация решения по управлению эффективностью бизнеса
  • Новые SerialATA-винчестеры
  • Карман для сервера

    1 марта

  • Выбрать корпус - нет ничего проще?
  • Создание виртуальной сети с удаленной загрузкой узлов
  • Текущее состояние и перспективы развития рынка интеграционных технологий
  • Интеграция корпоративной информации: новое направление
  • Архитектурные подходы к консолидации

    24 февраля

  • Каждому проекту своя методология
  • Императив интеграции
  • Безопасность IP-телефонии - полевые зарисовки
  • О злокозненности Билла Гейтса, или почему я не люблю Windows

    22 февраля

  • Oracle10: шифруем данные
  • В версии Oracle10 "виртуальные частные базы данных" данных стали избирательнее
  • Каждому (пользователю) свое (данное в таблице)
    Часть 1
    Часть 2
  • Ускоряем интернет
  • Сетевая аутентификация на практике
  • В фокусе Microsoft Virtual Server 2005

    17 февраля

    Открыт новый раздел
    Все об Open Source

    Все новости >>>



  • IT-консалтинг Software Engineering Программирование Open Source СУБД Безопасность Internet Сети Операционные системы Hardware

    Информация для рекламодателей PR-акции, размещение рекламы - pr@citforum.ru, тел. +7 095 4119920 Пресс-релизы - manager@citforum.ru
    Послать комментарий
    Информация для авторов
    Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
    Copyright © 1997-2000 CIT, © 2001-2004 CIT Forum
    Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...