Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Поиск директорий.


Автор: SeregaLBN 28.2.2006, 16:52
Собственно ф-ция написана (приведена ниже) - это обёртка над FindFirstFile, FindNextFile и FindClose.
Но в коде приходится делать проверку - не является ли указаное имя файлом...
Т.е., получается, для того чтобы перечислить все директории нужно перечислить и все файлы заодно.
А это меня не устраивает по скорости работы...

Как можно перечислять сразу только папки?


Я пытался использовать FindFirstFileEx, например, при таком вызове:
Код

   WIN32_FIND_DATA findFileData;
   HANDLE hFindFile = ::FindFirstFileEx(_T("C:\\"), FindExInfoStandard, &findFileData, FindExSearchLimitToDirectories, NULL, 0);

В результате hFindFile == INVALID_HANDLE_VALUE, а GetLastError() == ERROR_FILE_NOT_FOUND

А если делаю так:
Код

   WIN32_FIND_DATA findFileData;
   HANDLE hFindFile = ::FindFirstFileEx(_T("C:\\*"), FindExInfoStandard, &findFileData, FindExSearchLimitToDirectories, NULL, 0);

В результате hFindFile валидный, но всё равно приходится делать проверку:
Код

         if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {...}

т.к. приходят ещё и файлы.
Поэтому я для себя различий с FindFirstFile невижу...

Собственно, ф-ция поиска:
Код

typedef BOOL (CALLBACK* DIRENUMPROC )(IN LPCTSTR szDirName, IN LPCTSTR szSubDirName, IN LPVOID lpParam); // if return FALSE -> stop enumerators

BOOL EnumSubDir(IN LPCTSTR szDirName, IN DIRENUMPROC lpEnumFunc, IN LPVOID lpParam) {
   if (!szDirName || !szDirName[0] || !lpEnumFunc) {
      ::SetLastError(ERROR_INVALID_PARAMETER);
      return FALSE;
   }
   WIN32_FIND_DATA findFileData;
   HANDLE hFindFile = NULL;
   BOOL bRes = TRUE;
   DWORD dwErrCode = NO_ERROR;
   CString strDirName(szDirName);
   if (strDirName[strDirName.GetLength()-1] != _T('\\')) {
      strDirName += _T('\\');
   }
   do {
      if (hFindFile == NULL) {
         hFindFile = ::FindFirstFile(strDirName + _T('*'), &findFileData);
         bRes = (hFindFile != INVALID_HANDLE_VALUE);
      } else {
         bRes = ::FindNextFile(hFindFile, &findFileData);
      }
      if (!bRes) {
         DWORD dwErrCode = ::GetLastError();
         if (hFindFile == INVALID_HANDLE_VALUE) {
            if ((dwErrCode == ERROR_FILE_NOT_FOUND) ||
                (dwErrCode == ERROR_PATH_NOT_FOUND))
            {
               bRes = TRUE;
            }
         } else {
            if (dwErrCode == ERROR_NO_MORE_FILES) {
               bRes = TRUE;
            }
         }
         break;
      } else {
         if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            if (lstrcmp(findFileData.cFileName, _T(".")) &&
                lstrcmp(findFileData.cFileName, _T("..")))
            {
               bRes &= lpEnumFunc(szDirName, findFileData.cFileName, lpParam);
            }
            
         }
      }
   } while(bRes);
   if (hFindFile != INVALID_HANDLE_VALUE) {
      bRes = ::FindClose(hFindFile); hFindFile = NULL;
      if (!bRes) {
         dwErrCode = ::GetLastError();
         if (dwErrCode == ERROR_NO_MORE_FILES) {
            bRes = TRUE;
         }
      }
   }
   ::SetLastError(dwErrCode);
   return bRes;
}

Автор: Earnest 28.2.2006, 17:09
Цитата(MSDN)

FindExSearchLimitToDirectories
This is an advisory flag.
If the file system supports directory filtering, the function searches for a "file" that matches the specified file name and that is a directory.

If the file system does not support directory filtering, this flag is silently ignored.

The lpSearchFilter parameter of FindFirstFileEx must be NULL when this search operation is used.

If you want directory filtering, use this flag on all file systems, but be sure to examine the file attribute data stored into the *lpFindFileData parameter of FindFirstFileEx to determine whether the function has indeed returned a handle to a directory.

Особенно последние строки... smile

Автор: SeregaLBN 28.2.2006, 17:20
Цитата(Earnest @ 28.2.2006, 17:09 Найти цитируемый пост)
Цитата(MSDN)
If you want directory filtering, use this flag on all file systems, but be sure to examine the file attribute data stored into the *lpFindFileData parameter of FindFirstFileEx to determine whether the function has indeed returned a handle to a directory.
Особенно последние строки... smile

Блин, читал и не увидел..
Жаль...

Но всё равно главный вопрос остался:
Цитата(SeregaLBN @ 28.2.2006, 16:52 Найти цитируемый пост)
Как можно перечислять сразу только папки?

Может есть альтернатива FindFirstFile, FindNextFile и FindClose?

Автор: Earnest 28.2.2006, 17:40
Честно говоря, не знаю, да и не вижу смысла: твой код ведь работает? А если хочешь его структурировать получше - ну напиши сам функции FindFirstDir, FindNextDir.

Автор: adonin 1.3.2006, 12:54
Посмотрел File Functions в MSDN: ничего подходящего, кроме FindFirstFile, FindNextFile и FindClose не нашёл.
Поэтому ваш вариант - единственно правильный smile

Автор: Romikgy 1.3.2006, 13:50
Цитата(SeregaLBN @ 28.2.2006, 16:20 Найти цитируемый пост)
Может есть альтернатива FindFirstFile, FindNextFile и FindClose?

Есть листбокс smile

Автор: Fixin 2.3.2006, 19:44
Цитата(Romikgy @ 1.3.2006, 13:50 Найти цитируемый пост)
Есть листбокс
Он ищет так же.

Автор: Romikgy 3.3.2006, 11:52
Цитата(Fixin @ 2.3.2006, 18:44 Найти цитируемый пост)
Он ищет так же.

Может , зато пишется проще smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)