Иерархический список дерева папок с использованием Windows API

#c #recursion #winapi

#c #рекурсия #winapi

Вопрос:

Я использую этот код для рекурсивного перечисления папки и ее вложенных папок на C , код работает нормально, я изменил его из-за многих вопросов Stackoverflow о рекурсивном списке папок.

 #include <iostream>
#include <string>
#include <windows.h>

#ifndef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif  

void findFiles (const std::string amp; spath)
{

struct HandleWrapper
{
   HANDLE hFind;        
  ~HandleWrapper () {if (hFind != INVALID_HANDLE_VALUE) ::FindClose (hFind); } 
} wrapper;

size_t i = 1;
WIN32_FIND_DATA FindFileData;

std::string sourcepath = spath   std::string ("\*.*");
wrapper.hFind = FindFirstFile (sourcepath.c_str (), amp;FindFileData);


if (wrapper.hFind != INVALID_HANDLE_VALUE)

do
  {

  std::string fullpath =
  std::string (spath)   std::string ("\")   std::string (FindFileData.cFileName);

  if ((FindFileData.dwFileAttributes amp; FILE_ATTRIBUTE_DIRECTORY) amp;amp; std::string FindFileData.cFileName) != "." amp;amp; std::string (FindFileData.cFileName) != "..")
  
    findFiles (fullpath);

  else
   
    std::cout << i   << "-" << FindFileData.cFileName<<std::endl;
  
  } while (FindNextFile (wrapper.hFind, amp;FindFileData));

}

int main (int argc, char **argv)
{
std::string spath (argv[1]);
findFiles (spath);
return EXIT_SUCCESS;
}
  

Проблема в том, что у вас есть дерево, подобное этому:

 A file
B another file
C folder
D another folder
E file
F file
  

Эта программа перечислит, A and B затем она перейдет в C и любые подпапки, которые она может содержать, затем сделает то же самое для D затем она перечислит файлы ‘E и F’ в родительской папке, я действительно хочу, чтобы она перечисляла, A, B, E and F затем перейдите к подпапкам C and D .
Есть идея сделать это, не прибегая к внешним библиотекам?

Комментарии:

1. Просто разделите цикл do / while на два цикла. В первом цикле распечатайте все файлы и игнорируйте все папки. В секундном цикле игнорируйте все файлы и вызывайте рекурсивную функцию для каждой папки.

2. Вероятно, сначала следует решить проблему корректности. Вы никогда не сможете реализовать библиотеку управления файлами общего назначения, используя кодировку кодовой страницы. Тем не менее, зачем изобретать велосипед? C уже предоставляет вам все, что вам нужно.

3. Почему эти функции все еще существуют в API?

4. Потому что не каждая программа написана на C . И для тех программ, которые написаны на C , реализация файловой системы в конечном итоге должна будет обращаться к ОС. Языки программирования не живут в вакууме.

Ответ №1:

Как сказал @Shubham, вам нужно использовать очередь для выполнения нужной функции.

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

Вот пример:

 #include <Windows.h>
#include <iostream>
#include <queue>
using namespace std;
queue<std::string> qFolders;

void findFiles(string Path)
{
    WIN32_FIND_DATA findResu<
    HANDLE handle = NULL;

    if (qFolders.size() > 0)
    {
        std::string tempFolder = qFolders.front();
        tempFolder.append("\*.*");
        handle = FindFirstFile(tempFolder.c_str(), amp;findResult);
        cout << qFolders.front() << endl;
        do
        {
            if (findResult.dwFileAttributes amp; FILE_ATTRIBUTE_DIRECTORY)
            {
                if (lstrcmp(".", findResult.cFileName) == 0 || lstrcmp("..", findResult.cFileName) == 0)
                {
                    continue;
                }
                tempFolder = qFolders.front();
                tempFolder.append("\").append(findResult.cFileName);
                qFolders.push(tempFolder);
            }
            else {
                cout << "  " << findResult.cFileName << endl;
            }
        } while (FindNextFile(handle, amp;findResult));
        qFolders.pop();
        if(!qFolders.empty())
        {
            findFiles(qFolders.front());
        }
    }
    if (handle)
    {
        FindClose(handle);
        handle = NULL;
    }
}

int main()
{
    qFolders.push("D:\test\t");
    findFiles(qFolders.front());
    return 0;
}
  

Вывод:

введите описание изображения здесь

Комментарии:

1. Вы расширили мой ответ, не проголосовав за него 😞

Ответ №2:

Используйте очередь. Если вы обнаружите папку, поместите ее в очередь. Когда все дочерние элементы в текущем каталоге будут выполнены, извлеките их из очереди, погрузитесь в нее и повторите, больше похоже на модифицированную BFS.