Консультация № 174698
30.11.2009, 02:46
0.00 руб.
0 13 1
Добрый вечер Уважаемые эксперты. Пожалуйста помогите со следующей задачей:
Организовать поиск введенного с клавиатуры файла в введенной с клавиатуры директории и ее поддиректории.
(С использованием функций findfirst и findnext).
То, что удалось реализовать в приложении. программа ищет файл только в каталоге с одного слова. Например - C:\WORK\*, а C:\Program files\* не понимает. И обрывается на пробеле. Не понимаю в чем здесь проблема. А также не знаю как организовать поиск по поддиректориям. Заранее благодарен за помощь.



Приложение:
#include <stdio.h>
#include <stdlib.h>
#include <dir.h>
#include <iostream.h>
#include <string.h>
void main()
{
struct ffblk ffblk;
int d;
char maska[18];
cout << "Vvedite adres i masku :";
cin >> maska;
cout <<"\n";
cout << "\n----------------------\nV directoryi " << maska <<"\n----------------------\n";
d = findfirst(maska, &ffblk, 0);
while (!d)
{
cout <<"\n" << ffblk.ff_name;
d = findnext(&ffblk);
}
cout <<"\n----------------------\n";
}

Обсуждение

Неизвестный
30.11.2009, 06:48
общий
Dimon4ik:
cin >> maska;
Читает до первого разделителя. Пользуйтесь getline().
Неизвестный
30.11.2009, 07:26
общий
Для организации поиска по поддиректориям организуйте рекурсивную функцию, т.е. функцию которая вызывает сама себя для прохождения всего дерева каталогов.
Неизвестный
30.11.2009, 14:07
общий
Калеев Владимир Викторович:
А как сделать чтобы она опеределила какие там есть каталоги? И чтобы в них зашла?
Она же ищет только файлы. В уже известном каталоге, а про подкаталог как она может узнать?
Неизвестный
30.11.2009, 14:22
общий
Dimon4ik:
Для того чтобы функции findfirst и findnext искали каталоги нужно в атрибутах установить флаг FA_DIREC, который равен 0x10.
Таким образом мы в программе сначала вызываем функции findfirst и findnext без атрибутов и получаем список файлов в указанном каталоге, а затем вызываем те же функции но с атрибутом FA_DIREC, и получаем список подкаталогов в указанном каталоге. Далее мы проходим весь полученный список подкаталогов, и для каждого подкаталога вызываем "сами себя", т.е. функцию в которой мы находимся.
Неизвестный
30.11.2009, 16:37
общий
Dimon4ik:
если уж char используете. то задавайте либо так
char maska[MAX_PATH] = {0}; // MAX_PATH уточняйте в Вашем компиляторе/версии С библиотек, может быть MAXPATH
ну или char maska[255] = {0};
Но, коль уж пытаетесь на С++ писать, то вспомните о типе string
А что бы искало и в подкаталогах - надо использовать рекурсию.. Тут без неё родимой никак..
Неизвестный
30.11.2009, 17:12
общий
это ответ
Здравствуйте, Dimon4ik.

Судя про приведенному Вами исходнику, программа должна работать под DOS и компилироваться в Borland C++ (например, в MSVC++ 6.0 функции поиска и структуры другие). Приведенный мной код (см. приложение) может компилироваться как в MSVC++ 6.0, так и в Borland C++ (я проверял с версией 3.1). Но под DOS допустимые длины путей (_MAX_PATH определено как 80) меньше, чем под Windows, поэтому при попытке найти глубоко расположенный файл программа может повиснуть. При этом версия, скомпилированная в MSVC++ 6.0, работает нормально. Попытка переопределить _MAX_PATH на большее значение к успеху не привела. (Тут надо действовать по-другому — при входе в подкаталог, переопределять текущий каталог и выполнять поиск от него, а не от первоначально заданного пользователем, как в приведенной программе.)
Пример (версия для win32):

Path where to search: d:\windows
File to search: hosts

< ... пропущено... >

d:\windows\system32\dllcache\
d:\windows\system32\drivers\
d:\windows\system32\drivers\disdn\
d:\windows\system32\drivers\etc\

File 'hosts' has been found in 'd:\windows\system32\drivers\etc\'
Press [Enter] to exit...

Версия, скомпилированная в Borland C++ 3.1, при этих же входных данных у меня виснет (из-за длинных путей где-то в Microsoft.NET). Но, например, нормально находит bc.exe, начиная от C:\

Path where to search: c:\
File to search: bc.exe
c:\
c:\DOS\
c:\UTILS\
c:\ASM\
c:\BC\
c:\BC\BGI\
c:\BC\BIN\

File 'bc.exe' has been found in 'c:\BC\BIN\'
Press [Enter] to exit...

Кроме того, Borland C++ 3.1 ничего не знает о длинных именах. Поэтому, даже если Ваша версия DOS понимает длинные имена, о таких именах, в частности, о пробелах в имени, лучше забыть.

Как работает программа.
После запуска запрашиваются имена каталога и файла для поиска. Каталог можно вводить как с конечным '\', так и без него (добавляется при необходимости в программе). Имя файла должно быть именно именем файла, маски не поддерживаются. Затем вызывается функция поиска, которая рекурсивно обходит подкаталоги, пока искомый файл не найден. Функция ищет только первое вхождение файла. Если нужно найти все файлы с заданным именем (их может быть несколько в разных подкаталогах), то надо

if( search( subdir, filename ) == 0 )
return 0; // файл был найден в каком-то подкаталоге

заменить на

search( subdir, filename );

а также или убрать сообщение "File not found", или устанавливать какой-либо флаг "найден/не найден".

Проверка на метку тома введена для гарантии (метка тома может встретиться только один раз в корневом каталоге диска).

Успехов!


Приложение:
/*
Организовать поиск введенного с клавиатуры файла
в введенной с клавиатуры директории и ее поддиректории.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __TURBOC__

#include <dir.h>
#include <dos.h>

#define _finddata_t ffblk
#define FF_ATTRIB ff.ff_attrib
#define FF_NAME ff.ff_name

#else // подразумеваем Windows

#include <io.h>

#define FF_ATTRIB ff.attrib
#define FF_NAME ff.name

#endif


int search( char* path, char* filename )
{
puts( path ); // для информации

char mask[_MAX_PATH];
// формируем маску
// нам надо с заходом в подкаталоги, поэтому "*.*"
strcat( strcpy( mask, path ), "*.*" );

_finddata_t ff;
#ifdef __TURBOC__
int h = findfirst( mask, &ff, FA_RDONLY | FA_HIDDEN | FA_SYSTEM | FA_DIREC | FA_ARCH );
#else
long h = _findfirst( mask, &ff );
#endif
if( h == -1 ) return -1; // файлы не найдены
do {
if( FF_ATTRIB & _A_SUBDIR ) { // подкаталог
// подкаталог
// если имя не "." и не "..", то заходим в него
// такой способ быстрее, чем вызов strcmp()
if( *(short*)FF_NAME != *(short*)"." &&
(*(short*)FF_NAME != *(short*)".." || FF_NAME[2] != '\0') )
{
char subdir[_MAX_PATH];
sprintf( subdir, "%s%s\", path, FF_NAME );
if( search( subdir, filename ) == 0 )
return 0; // файл был найден в каком-то подкаталоге
}
}
else if( !(FF_ATTRIB & 0x08) ) { // не метка тома
if( strcmpi( FF_NAME, filename ) == 0 ) {
printf( "\nFile '%s' has been found in '%s'\n", filename, path );
return 0;
}
}
#ifdef __TURBOC__
} while( findnext( &ff ) == 0 );
#else
} while( _findnext( h, &ff ) == 0 );
_findclose( h );
#endif
return -1;
}


int main()
{
char path[_MAX_PATH], filename[_MAX_FNAME];

printf( "Path where to search: " );
gets( path );
printf( "File to search: " );
gets( filename );

int n = strlen( path );
if( path[n-1] != '\\' )
*(short*)&path[n] = *(short*)"\";

if( search( path, filename ) < 0 )
printf( "\nFile '%s' is not found.\n", filename );

printf( "Press [Enter] to exit..." );
getchar();
return 0;
}
5
Отличная программа! Большое спасибо! Я пошел разбираться.
Неизвестный
01.12.2009, 00:21
общий
amnick:
Пожалуйста обьясните вот эти строки:

#define _finddata_t ffblk
#define FF_ATTRIB ff.ff_attrib
#define FF_NAME ff.ff_name

и то что дальше происходит связаное с этим. Например: finddata_t ff;
Вот это сравнение тоже не очень понял:
if( FF_ATTRIB & _A_SUBDIR )
Неизвестный
01.12.2009, 15:11
общий
Dimon4ik:
Программа может компилироваться как в Borland C++ 3.1, так и в MSVC++ 6.0, поэтому, чтобы уменьшить число #ifdef/#else/#endif в самом коде, сделаны эти определения в начале файла. Это связано с тем, что соответствующие структуры данных различны в Borland C++ 3.1 и MSVC++ 6.0 — различны имена структур, имена членов и т.д. Частично это объясняется разными операционными системами (структуры для findfirst/findnext различны в DOS и Windows), а частично (имена соответствующих членов) — просто тем, что это компиляторы разных фирм. Вы же не уточнили, под какой компилятор и какую OC надо писать программу, поэтому я и сделал версию "два в одном". При компиляции в Borland C++ символ __TURBOC__ предопределен (номер версии компилятора) и используются соответствующие подстановки.
Впрочем, если Вы сумеете защитить работу, то это должно пойти Вам в плюс.
Неизвестный
01.12.2009, 15:28
общий
Цитата: 218629
это сравнение тоже не очень понял:
if( FF_ATTRIB & _A_SUBDIR )

Каждый файл в DOS или Windows имеет набор признаков — атрибутов (системный, только для чтения, скрытый и т.д.) Подкаталог — это тоже файл, только специального вида, содержащий информацию о других файлах. Помечается такой файл соответствующим атрибутом — _A_SUBDIR, что и проверяется в этом условном операторе. FF_ATTRIB разворачивается компилятором или в ff.ff_attrib (Borland C++), или в ff.attrib (MSVC++ 6.0).

Далее, в начале каждого подкаталога есть 2 специальных элемента — ссылки на себя (.) и на родительский каталог (..). Эти 2 элемента должны быть исключены из рекурсивного обхода, что обеспечивается условием
Код:

if( *(short*)FF_NAME != *(short*)"." &&
(*(short*)FF_NAME != *(short*)".." || FF_NAME[2] != '\0') )


Это условие равносильно
if( strcmp( FF_NAME, "." ) && strcmp( FF_NAME, ".." ) )
но выполяется быстрее, чем обращение к strcmp().
Неизвестный
03.12.2009, 14:12
общий
amnick:
В принципе суть понятна
Спасибо.
Неизвестный
03.12.2009, 14:55
общий
amnick:
А Вы бы не могли бы подсказать где можно почитать про данные обозначения, функции, типы и т д?
Неизвестный
03.12.2009, 17:03
общий
Цитата: 218629
А Вы бы не могли бы подсказать где можно почитать про данные обозначения, функции, типы и т д?

А Вы не могли бы уточнить, что Вы подразумеваете под "данными обозначениями"?

Что касается функций, типов — при программировании под Windows, первоисточник информации — MSDN (на английском), часть информации доступна на русском языке. Для уточнения (и в MSDN бывают ошибки или непонятки) иногда приходится лезть в заголовочные файлы.

Можно почитать книги, но Вы так и не уточнили ни ОС, ни среду разработки, чтобы предложить что-то конкретное. Далее, судя по тому, что рекурсия вызвала у Вас затруднения, стоит почитать книги по программированию, что-нибудь для начинающих. Очень полезно разбирать исходники не слишком сложных демонстрационных программ.

Учитесь пользоваться поиском. Задайте поиск, например в Google, "программирование для начинающих". Получите кучу ссылок. Например, менее чем за 1мин я нашел
- C++ для начинающих (явно какая-то книга в электронном виде; ссылка на автора лихо запрятана или ее вообще нет, что плохо);
- Учебник по C++ для начинающих
- Справочники и учебники
и др. Это просто примеры, и не более того. В Интернете море информации!
Неизвестный
03.12.2009, 17:09
общий
данные обозначения

К этому можно отнести такие слова как :
_A_SUBDIR, 0x08 ...
Спасибо. Я понял где искать.
Форма ответа