• Forum
  • Jobs
  • How to display all files, subfiles and d

 
How to display all files, subfiles and directories

I know about FindFirstFile/FindNextFile, so how can i display along the path, for example, C:\Program Files\, all folders and all files enclosed within them, in general, all directories and files along this path. Using only WinAPI + FindFirstFile/FindNextFile, without Boost/Filesystem/dirent.h and etc. Looks like a recursion output with dirent.h, such as:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include "iostream"
#include "string"
#include <windows.h>
#include <fstream>

using namespace std;
void listFilesRecursively(char *path);
int main()
{
  setlocale(LC_ALL , "Russian");
    char path[100];
    printf("Enter path to list files: ");
    scanf("%s", path);
    listFilesRecursively(path);
    return 0;
}
void listFilesRecursively(char *basePath)
{
     WIN32_FILE_ATTRIBUTE_DATA Info;
     char path[1000];
     struct dirent *dp;
     DIR *dir = opendir(basePath);
    if (!dir)
        return;
    while ((dp = readdir(dir)) != NULL)
    {
        if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
        {
            printf("%s\n", dp->d_name);

            strcpy(path, basePath);
            strcat(path, "/");
            strcat(path, dp->d_name);

            string path_s = (const char*) path;
            GetFileAttributesEx(path_s.c_str(), GetFileExInfoStandard, &Info);
            cout<<Info.nFileSizeLow<<endl;
            listFilesRecursively(path);
        }
    }

    closedir(dir);
}


But how to do this using only WinAPI?

I tried like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <Windows.h>
#include <iostream>
#include <string>
#include <vector>    

void FindFile(const std::wstring &directory)
{
    std::wstring tmp = directory + L"\\*";
    WIN32_FIND_DATAW file;
    HANDLE search_handle = FindFirstFileW(tmp.c_str(), &file);
    if (search_handle != INVALID_HANDLE_VALUE)
    {
        std::vector<std::wstring> directories;

        do
        {
            if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            {
                if ((!lstrcmpW(file.cFileName, L".")) || (!lstrcmpW(file.cFileName, L"..")))
                    continue;
            }

            tmp = directory + L"\\" + std::wstring(file.cFileName);
            std::wcout << tmp << std::endl;

            if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                directories.push_back(tmp);
        }
        while (FindNextFileW(search_handle, &file));

        FindClose(search_handle);

        for(std::vector<std::wstring>::iterator iter = directories.begin(), end = directories.end(); iter != end; ++iter)
            FindFile(*iter);
    }
}

int main()
{
    FindFile(L"C:");
    return 0;
}

But it only displays if the path is in the form of "C:\" and does not display subfolders with files.
Last edited on
You can do this with plain C++17.

1
2
3
4
5
6
7
8
9
#include <string>
#include <iostream>
#include <filesystem>

int main() {
	std::string path = "C:/";
	for (const auto & entry : std::filesystem::recursive_directory_iterator(path))
			std::cout << entry.path() << std::endl;
}
wow, you reduced OP's code into 2 lines??
now that's the power of modern C++, huzzah!!!
Last edited on
I suppose that separate string isn't really necessary... :)

1
2
3
4
5
6
7
#include <iostream>
#include <filesystem>

int main() 
{
	for (const auto & entry : std::filesystem::recursive_directory_iterator("C:/")) std::cout << entry.path() << std::endl;
}
Last edited on
That is so very nice! I remember letting the OS do this for me to a text file to avoid the pain back long long ago...
Repeater, thank you! But i wrote "without Boost/Filesystem/dirent.h and etc" and "using WinAPI only". it is necessary and spelled out in my assignment. I tried to do using dirent.h and i made it, but the teacher said to do only using WinAPI with FindFirstFile/FindNextFile, after I tried to do it using WinAPI, but the program does not display all the files.
C++, unfortunately, is not my core language.
what is it missing?
winapi isnt c++, its a library. The core language isnt the problem here.
Last edited on
Unfortunately, this is the task, only WinAPI... Well will try to do this. Thanks all <3
You've already written it. You just need to call FindFile for each directory you find.

Each time you find a directory, add it to a vector of them. Something like this.
1
2
3
4
5
6
7
8
  if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            {
                if ((!lstrcmpW(file.cFileName, L".")) || (!lstrcmpW(file.cFileName, L"..")))
                {
                      directories.append(THE_DIRECTORY_PATH); // ADD THE FOUND DIRECTORY TO YOUR VECTOR
                      continue;
                 }
            }



Your outer loop keeps going until there are no more directories.
1
2
3
4
5
6
7
8
 vector<string> directories;  // THIS is the directory vector to add to. You work out how to pass it to the FindFile function
  directories.push_back("C:");
  while (directories.size() > 0)
  {
     string next_dir = directories.back();
     directories.pop_back();
     FindFile(next_dir);
  }
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <string>
#include <windows.h>
#include <memory>

void list_files_under( const std::string& path_to_dir, const std::string& tab = {} )
{
    const auto name = path_to_dir + "\\*" ; // append wild card to the directory path

    WIN32_FIND_DATAA find_data ;
    const auto handle = FindFirstFileA( name.c_str(), std::addressof(find_data) ) ;

    if( handle == INVALID_HANDLE_VALUE ) return ; // TO DO: GetLastError, emit error diagnostic etc.

    do
    {
        if( find_data.cFileName[0] != '.' ) // skip "." and ".."
        {
            std::cout << tab << find_data.cFileName << "    " ;

            if( find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
            {
                std::cout << "<DIR>\n" ;
                list_files_under( path_to_dir + '\\' + find_data.cFileName, tab + "    " ) ;
            }

            else std::cout << find_data.nFileSizeLow << " bytes\n" ; // TO DO: take care of huge files
        }
    }
    while( FindNextFile( handle, std::addressof(find_data) ) ) ;

    FindClose(handle) ;
}

int main()
{
    const std::string directory = "c:\\program files" ;
    std::cout << "files under directory: " << directory << "\n---------------\n\n" ;
    list_files_under(directory) ;
}

https://rextester.com/SCPZF66048
JLBorges, hello!
There are two errors:
Error E0167 argument of type "WIN32_FIND_DATAA *" is incompatible with parameter of type "LPWIN32_FIND_DATAW"
Error C2664 "BOOL FindNextFileW (HANDLE, LPWIN32_FIND_DATAW)": cannot convert argument 2 from "_Ty *" to "LPWIN32_FIND_DATAW" with [_Ty = WIN32_FIND_DATAA]
Both relate to the string 29
while (FindNextFile(handle, std::addressof(find_data)));
Last edited on
I made a careless mistake (or in American: my careless bad); should have used the narrow character functions consistently.

Change to FindNextFileA and the error will go away.
1
2
// while( FindNextFile( handle, std::addressof(find_data) ) ) ;
while( FindNextFileA( handle, std::addressof(find_data) ) ) ;


https://rextester.com/HYQBX15361
Dear Sir JLBorges, you wonderful C++ wizard! THANK YOU!
It great works!!!
I want to say thanks to this forum, which the 6th programming portal and where i finally got help!
I also express my gratitude to everyone who somehow answered me in this thread!
Topic archived. No new replies allowed.