Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Поиск файлов и сверка с базой сигнатур, По типу антивируса 
:(
    Опции темы
VIAL
Дата 5.7.2005, 05:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 5.7.2005

Репутация: нет
Всего: нет



Поиск файлов и сверка с базой сигнатур

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

Код

#include <fstream.h>
#include <windows.h>

//Кол-во используемых сигнатур
const unsigned int iVBases = 10;
//Значение высчитанной сигнатуры
unsigned long int m_liSign;
//Указатель на строку с путем до файла
char* m_cString;
//Массив из сигнатур в имеющейся базе
unsigned long int m_liCheck[iVBases];

/*    допустим, уже есть функция проверки, 
    возвращающая значение в переменных
    m_liSign и m_cString. Функция Sign -
    заглушка
*/
void Sign()
{
    // Ищем файлы
    m_cString = "C:\\game.exe"; //remove
    // и считаем сигнатуру
    m_liSign = 12; //remove

    //цикл сверки сигнатуры файла с базой из iVBases сигн.
    for(int m_is=0;m_is<iVBases;m_is++)
    {
        if(m_liSign==m_liCheck[m_is])
        {
        // если равно, сообщаем
        MessageBox(NULL, "Find", "OK", MB_OK); //remove
        MessageBox(NULL, m_cString, "D", MB_OK); //remove
        }
    }
}

void main()
{
    unsigned long int m_liDig;
    // поток для чтения данных
    ifstream f_in;
    //Подсоединяем его к файлу
    f_in.open("bases.txt");
        
    for(int m_ii=0;m_ii<iVBases;m_ii++)
    {    // читаем из потока число
        f_in >> m_liDig;
        // организуем массив
        m_liCheck[m_ii] = m_liDig;
        // показываем значение сигнатуры на экране
        cout << m_liDig << "\n"; //remove
    }
    //Закрываем поток для чтения
    f_in.close();

/*
    В массиве m_liCheck 
    записаны значения iVBases первых сигнатур.
*/

    // теперь сравниваем
    Sign();
}



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

Загвоздка возникла с реализацей функции поиска. Посмотрел в MSDN _findfile, _nextfile. Попытался реализовать - возникла ошибка. Скорее всего, я не понял, как их использовать.
Нашел в форуме код для Builder и переделал для M$VS - на чем пишу программу:

Код


void FindDir(char* path,char* mask)    
{    
WIN32_FIND_DATA wfd;    
HANDLE hfound;    
char newpath[MAX_PATH];    
char fpath[MAX_PATH];    
char delpath[MAX_PATH];    
strcpy(fpath,path);    
strcat(fpath,"\\");    
strcpy(delpath,fpath);    
strcat(fpath,mask);    
if((hfound=FindFirstFile(fpath,&wfd))!=INVALID_HANDLE_VALUE)    
{    
if(!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)&&strcmp(wfd.cFileName,"..")&&strcmp(wfd.cFileName,"."))    
{    
//нашли первый файл в папке path    
    MessageBox(NULL, delpath, wfd.cFileName, MB_OK);
//    
}    
while(FindNextFile(hfound,&wfd))    
{    
if(!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)&&strcmp(wfd.cFileName,"..")&&strcmp(wfd.cFileName,"."))    
{    
//нашли ещё файл в папке path    
//        TestFile(delpath,wfd.cFileName);    
//Здесь заглушка в виде Message Box для примера
        MessageBox(NULL, wfd.cFileName, delpath, MB_OK);
        //delpath - папка, с которой начинается реккурсия
        //wfd.cFileName - имя найденного файла
        //Здесь ПРОВЕРКА
}    
}    
}    
FindClose(hfound);    
//поиск файлов закончили, теперь ищем подпапки    
strcpy(fpath,path);    
strcat(fpath,"\\*.*");    
if((hfound=FindFirstFile(fpath,&wfd))!=INVALID_HANDLE_VALUE)    
{    
if((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)&&strcmp(wfd.cFileName,"..")&&strcmp(wfd.cFileName,"."))    
{    
strcpy(newpath,path);    
strcat(newpath,"\\");    
strcat(newpath,wfd.cFileName);    
FindDir(newpath,mask); //Рекурсивный вызов    
}    
while(FindNextFile(hfound,&wfd))    
{    
if((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)&&strcmp(wfd.cFileName,"..")&&strcmp(wfd.cFileName,"."))    
{    
strcpy(newpath,path);    
strcat(newpath,"\\");    
strcat(newpath,wfd.cFileName);    
FindDir(newpath,mask); //Рекурсивный вызов    
}    
}    
}    
}    


void CMy34Dlg::OnButton1() 
{

    char* path = "C:\\";
         char* mask = "*.*";    
         FindDir(path,mask); //Вызов функции поиска и вывода файлов в директории    
}

Вопрос в том, какой алгоритм поиска быстрее. Натолкните, пожалуйста.

Это сообщение отредактировал(а) VIAL - 5.7.2005, 06:59
PM MAIL   Вверх
En_t_end
Дата 5.7.2005, 07:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 2074
Регистрация: 4.12.2004

Репутация: 1
Всего: 20



Мне показалось, что у тебя слишком действий происходит в поиске. На самом деле чистый поиск - это тоже самое, что в проводнике папку открыть. Поэтому вся ответсвенность за "тормоза" ложиться на сверку параметров. ... А дык тут у тебя рекурсия smile ? Дык ведь это же самое тормозное место в программе! Попробуй избавиться от рекурсии и сократи кол-во вызовов других фукций.
PM MAIL ICQ Skype GTalk Jabber   Вверх
VIAL
Дата 5.7.2005, 09:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 5.7.2005

Репутация: нет
Всего: нет



Понятное дело, что рекурсия - тормоз. А как от нее избавиться, если надо целый диск, начиная с корня проверить?

Как быть в случае с большой базой сигнатур?

Вот немного подправил, чтобы хоть работало.

В каталоге C:\11\ для демонстрации работы должно находиться два txt-файла с таким _целочисленным_ содержанием:

первый

222052120

и второй соответственно

35432457667567765765765

(без переноса каретки и пробелов)

В файле сигнатур одну из десяти первых следует выбрать 48
Максимальное значение сигнатуры (unsigned long int) равно 4294967295

Код

#include <fstream.h>
#include <windows.h>

//Кол-во используемых сигнатур
const unsigned int iVBases = 10;

//Массив из сигнатур в имеющейся базе
unsigned long int m_liCheck[iVBases];

// Указатель к каталогу, в котором
// будет произведен рекурсивный поиск
char* path = "C:\\11";

// Маска рекурсивного поиска
char* mask = "*.*";


/*    Необходимо лишь написать функцию
    подсчета сигнатур проверяемых файлов.
    Допустим, уже есть функция проверки,
    принимающая значение  wfd.cFileName,
    высчитывающая сигнатуру и
    возвращающая значение в переменной
    m_liSign. Функция Sign - на данный
    момент - заглушка.
*/

// функция рекурсивного поиска
void FindDir(char* path,char* mask)    
{    
    WIN32_FIND_DATA wfd;    
    HANDLE hfound;    
    char newpath[MAX_PATH];    
    char fpath[MAX_PATH];    
    char pathifile[MAX_PATH]; //полный путь до файла
    char delpath[MAX_PATH];    
    strcpy(fpath,path);    
    strcat(fpath,"\\");    
    strcpy(delpath,fpath);    
    strcat(fpath,mask);    


    if((hfound=FindFirstFile(fpath,&wfd))!=INVALID_HANDLE_VALUE)    
        {
        if(!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)&&strcmp(wfd.cFileName,"..")&&strcmp(wfd.cFileName,"."))    
            {
            //    
            }
        while(FindNextFile(hfound,&wfd))    
            {    
            if(!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)&&strcmp(wfd.cFileName,"..")&&strcmp(wfd.cFileName,"."))    
                {
                // файл в папке path    
                // delpath - папка, с которой начинается реккурсия
                // wfd.cFileName - имя найденного файла

                // копируем строку delpath в pathifile
                strcpy(pathifile, delpath);
                // прибавляем к строке pathifile значение
                // переменной wfd.cFileName - имя файла
                strcat(pathifile, wfd.cFileName);        
                
                //---------------------------------------------------------------//
                // глупый пример подсчета контрольной суммы. Следует заменить    //
                //---------------------------------------------------------------//
                // эта переменная служит для помощи подсчета КС
                char m_cFload;
                
                // переменная хранит КС
                unsigned long int m_iSign;

                //Открываем файл для чтения
                ifstream s_in(pathifile);
                //Читаем из него символы до конца файла
                //
                while(!s_in.eof())
                    {
                    s_in >> m_cFload; //Читаем символ
                    
                    if(!s_in.eof())
                        {
                        m_iSign = m_cFload; //и присваиваем переменной
                        }
                    //Закрываем поток
                    }
                s_in.close();
                
                // пишем на экране статистику для красоты
                cout << "Find:\n" << pathifile << "\t" << m_iSign <<"\n" << endl;

                // начинаем сверку с массивом базы данных
                for(int m_is=0;m_is<iVBases;m_is++)
                {
                    if(m_iSign==m_liCheck[m_is])
                    {
                        // если совпало, сообщаем
                        MessageBox(NULL, pathifile, "Игрушка", MB_OK); //change
                    }
                }
                

                }
            }
        }
        
    FindClose(hfound);    
    //поиск файлов закончили, теперь ищем подпапки    
    strcpy(fpath,path);    
    strcat(fpath,"\\*.*");    
    
    if((hfound=FindFirstFile(fpath,&wfd))!=INVALID_HANDLE_VALUE)    
        {
        if((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)&&strcmp(wfd.cFileName,"..")&&strcmp(wfd.cFileName,"."))    
            {
            strcpy(newpath,path);    
            strcat(newpath,"\\");    
            strcat(newpath,wfd.cFileName);    
            FindDir(newpath,mask); //Рекурсивный вызов    
            }
        
        while(FindNextFile(hfound,&wfd))    
            {
            if((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)&&strcmp(wfd.cFileName,"..")&&strcmp(wfd.cFileName,"."))    
                {
                strcpy(newpath,path);    
                strcat(newpath,"\\");    
                strcat(newpath,wfd.cFileName);    
                FindDir(newpath,mask); //Рекурсивный вызов    
                }
            }
        }
    // чтобы консоль не закрылась сразу
    Sleep(2000); // remove
    }    
    

void main()
{
    unsigned long int m_liDig;
    // поток для чтения данных
    ifstream f_in;
    //Подсоединяем его к файлу
    f_in.open("bases.txt");
        
    for(int m_ii=0;m_ii<iVBases;m_ii++)
    {    // читаем из потока число
        f_in >> m_liDig;
        // организуем массив
        m_liCheck[m_ii] = m_liDig;
        // показываем значение сигнатур базы на экране
        //cout << m_liDig << "\n"; //remove
    }
    //Закрываем поток для чтения
    f_in.close();

/*
    В массиве m_liCheck 
    записаны значения iVBases сигнатур.
*/

    // теперь ищем
    //
     FindDir(path,mask); //Вызов функции поиска и вывода файлов в директории    
}



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

PM MAIL   Вверх
vadims
Дата 9.7.2005, 19:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 305
Регистрация: 8.6.2005

Репутация: 2
Всего: 17



VIAL

ИМХО

1. Код приведенный в самом вопросе вообще задачи не решает
2. На самом поиске/переборе файло ты уже ничего не оптимизируешь - тут у тебя минимально возможный и необходимый набор операций для этого. Пытаться оптимизировать нужно уже непосредственно работу с найденным файлом - если это возможно - нет, значит ты достиг "предела совершенству". Можно конечно реализовать рекурсии через итерации, но там другие вопросы вылезут
3. Сам код перебора я бы сделал покрасивше, а именно - у тебя в текте будут повторять ся одни и те же операции после FindFirstFile и FindNextFile

Я бы сделал как то так

hfound=FindFirstFile(...)
while( hfound )
{

. . . // работа с найденным файлом


hfound=FindNextFile(...)
}


--------------------
Cpu not found ! Press any key for software emulation.
PM MAIL   Вверх
VIAL
Дата 10.7.2005, 23:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 8
Регистрация: 5.7.2005

Репутация: нет
Всего: нет



Спасибо. Поправим.
PM MAIL   Вверх
comcon1
Дата 12.7.2005, 12:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: 12
Всего: 17



Оптимизировать поиск можно, но поиск В БАЗЕ!! Я так понимаю, база будет большая, не 10 элементов. Организуй ее как std::set - поиск в этом контейнере проходит за логарифмическое время.
И используй вместо обычных вызовов - системные. Типа open, close. Так точно быстрее пойдет.


--------------------
PM MAIL   Вверх
vadims
Дата 12.7.2005, 12:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 305
Регистрация: 8.6.2005

Репутация: 2
Всего: 17



comcon1 В смысле в базе - не вьехал какую базу ты имеешь в виду ??? Предлагаешь копию структуры файлов-каталогов делать - а обновлять как ?? Или что ???


--------------------
Cpu not found ! Press any key for software emulation.
PM MAIL   Вверх
comcon1
Дата 12.7.2005, 12:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: 12
Всего: 17



Ну он вычисленную контр. сумму ищет в своей базе данных - в массиве каком-то из 10 элементов.

Но, я так понимаю, это заглушка, а в реал-проге этот массив будет скачиваться из файла и будет большим. И поиск вычисленной контрсуммы в нем надо проводить биарный, а не переборный. Я это имел в виду.

Это сообщение отредактировал(а) comcon1 - 12.7.2005, 12:29


--------------------
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0691 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.