28

I'm looking to list and store the contents of a directory in a struct using C on Windows.

I'm not necessarily looking for anyone to write out the code I'm looking for, rather point me in the right direction when it comes to which library I should be looking at.

I've been Googling for a few hours now and all I'm finding is C#, C++ solutions so any help would be greatly appreciated.

Flyer1
  • 847
  • 3
  • 10
  • 14

3 Answers3

56

Just like everyone else said (with FindFirstFile, FindNextFile and FindClose)... but with recursion!

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

bool ListDirectoryContents(const char *sDir)
{
    WIN32_FIND_DATA fdFile;
    HANDLE hFind = NULL;

    char sPath[2048];

    //Specify a file mask. *.* = We want everything!
    sprintf(sPath, "%s\\*.*", sDir);

    if((hFind = FindFirstFile(sPath, &fdFile)) == INVALID_HANDLE_VALUE)
    {
        printf("Path not found: [%s]\n", sDir);
        return false;
    }

    do
    {
        //Find first file will always return "."
        //    and ".." as the first two directories.
        if(strcmp(fdFile.cFileName, ".") != 0
                && strcmp(fdFile.cFileName, "..") != 0)
        {
            //Build up our file path using the passed in
            //  [sDir] and the file/foldername we just found:
            sprintf(sPath, "%s\\%s", sDir, fdFile.cFileName);

            //Is the entity a File or Folder?
            if(fdFile.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
            {
                printf("Directory: %s\n", sPath);
                ListDirectoryContents(sPath); //Recursion, I love it!
            }
            else{
                printf("File: %s\n", sPath);
            }
        }
    }
    while(FindNextFile(hFind, &fdFile)); //Find the next file.

    FindClose(hFind); //Always, Always, clean things up!

    return true;
}

ListDirectoryContents("C:\\Windows\\");

And now its UNICODE counterpart:

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

bool ListDirectoryContents(const wchar_t *sDir)
{ 
    WIN32_FIND_DATA fdFile; 
    HANDLE hFind = NULL; 

    wchar_t sPath[2048]; 

    //Specify a file mask. *.* = We want everything! 
    wsprintf(sPath, L"%s\\*.*", sDir); 

    if((hFind = FindFirstFile(sPath, &fdFile)) == INVALID_HANDLE_VALUE) 
    { 
        wprintf(L"Path not found: [%s]\n", sDir); 
        return false; 
    } 

    do
    { 
        //Find first file will always return "."
        //    and ".." as the first two directories. 
        if(wcscmp(fdFile.cFileName, L".") != 0
                && wcscmp(fdFile.cFileName, L"..") != 0) 
        { 
            //Build up our file path using the passed in 
            //  [sDir] and the file/foldername we just found: 
            wsprintf(sPath, L"%s\\%s", sDir, fdFile.cFileName); 

            //Is the entity a File or Folder? 
            if(fdFile.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY) 
            { 
                wprintf(L"Directory: %s\n", sPath); 
                ListDirectoryContents(sPath); //Recursion, I love it! 
            } 
            else{ 
                wprintf(L"File: %s\n", sPath); 
            } 
        }
    } 
    while(FindNextFile(hFind, &fdFile)); //Find the next file. 

    FindClose(hFind); //Always, Always, clean things up! 

    return true; 
} 
 
ListDirectoryContents(L"C:\\Windows\\");
NTDLS
  • 4,757
  • 4
  • 44
  • 70
  • 2
    The first example - u will need `stdio.h` and `windows.h` otherwise compile-able through g++ with no prob and **works** :) – jave.web Mar 03 '15 at 03:11
  • i met a problem. my win7 uses cp950 (traditional chinese) as its native encoding, when tried to list files with names encoded in cp1386 (simplified chinese). FindFirstFile/FindNextFile always try to transcode them to the native encoding, problem is they could not be used to open the files. Is there any way to prohibit this? i use mingw. – user693986 Jan 06 '17 at 23:26
  • Wait; so Windows API only allows looking at directories one file at a time? There's no way to get all the current directory data in one call? O.o – Dmytro Jun 30 '17 at 17:53
  • @Dmitry You could create a function that encapsulates the enumeration and have it return an array of strings for each file path. Generally speaking, enumerating a small directory doesn't take long at all - but it could take quite a while for a deep structure. So, if you go for the "one call" method - be sure to bake in some progress reporting. – NTDLS Jun 17 '19 at 15:08
  • 1
    Hey sorry for kicking an old question, but ‘FindFirstFile‘ requires that “the user must have access permissions to the root and all subdirectories on the path”. But how can I handle a case where I don’t have permissions for a single file in the directory? – Dniel BV Oct 30 '22 at 13:15
  • 2
    @DnielBV from a bit of testing, if you do not have permission to a file - you can sill see it and this will list it. If you do not have permission to a directory, you can also see it - but not its contents so a call to FindFirstFile for the directory for which you lack permission will return NULL. If you are looking to determine if you can read/write a file maybe check the _access function. there are some good docs on MSDN on the article for _access that may point you in the right direction. – NTDLS Nov 28 '22 at 17:11
7

Probably You are looking for these functions: FindFirstFile, FindNextFile, and FindClose.

Czipperz
  • 3,268
  • 2
  • 18
  • 25
lollinus
  • 434
  • 4
  • 11
6

To list file contents you can search a directory with these APIs: FindFirstFileEx, FindNextFile and FindClose. You'll need to #include <windows.h>, that'll get you access to the Windows API. They're C functions and so compatible with C++. If you want "specifically C++", try searching for listing directories using MFC.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115