Joseph Smith
Joseph Smith

Reputation: 139

Methods to iterate every file in a directory?

I've been looking around for methods by which a directory can be monitored for file creation/modification etc. however all the previous posts I've found for Windows are C++ specific.

Microsoft does list ReadDirectoryChangesW, but this too is for C++ (I haven't the knowledge to assess whether these are compatible for C). I've only knowledge with inotify for Linux, which is fairly straightforward, and wondered if there are any simple examples of the Windows equivalent? (I do not want to use inotify on Windows despite it technically being achievable).

Upvotes: 0

Views: 2292

Answers (2)

Mou
Mou

Reputation: 165

Using FindFirstFile to hit the first node of certain directory, then to call FindNextFile to iterate files one by one inside one directory layer. Here is my sample code for your reference, there is a recursive funcion.

#include "stdafx.h"
#include <string>
static void iterate_dir(std::string dir) {
    WIN32_FIND_DATA  fd;
    HANDLE hFind;
    std::wstring fn_ws;
    std::string fn;
    int pos = 0;
    int count_bg = 0;
    int count_fg = 0;
    std::string dir_bkp = dir;
    std::string dir_sub;

    std::string str_wide_char_for_any = "*.*";
    std::string str_folder_node = "..";

    if (dir.length() - dir.find_last_of("\\") > 1) //dir ends without "\\"
        dir +=  "\\";

    dir +=  str_wide_char_for_any;
    std::wstring dir_wstr = std::wstring(dir.begin(), dir.end());
    LPCWSTR dir_wc = dir_wstr.c_str();

    hFind = FindFirstFile(dir_wc, &fd);
    if (hFind == INVALID_HANDLE_VALUE) {
        FindClose(hFind);
        return;
    }
    while(true) {
        if (!FindNextFile(hFind, &fd)) {
            break;
        }
        if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
            fn_ws = std::wstring(fd.cFileName);
            fn = std::string(fn_ws.begin(), fn_ws.end());
            if (fn.compare(str_folder_node) == 0) {
                continue;               
            }
            else {
                if ((pos = dir.rfind(str_wide_char_for_any)) != std::string::npos) {
                    dir_sub = dir;
                    dir_sub = dir_sub.replace(dir_sub.begin()+pos, dir_sub.end(), fn.begin(), fn.end());
                }
                else if (dir.length() - (pos = dir.rfind("\\")) > 1) {
                    dir_sub = dir;
                    dir_sub += "\\";
                    dir_sub += fn;
                }
                else {  
                    dir_sub = dir;
                    dir_sub += fn;
                }
                printf("[%s][directory]:%s\n", __func__, dir.c_str());
                iterate_dir(dir_sub);
                continue;
            }
        }
        else if (fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {
            fn_ws = std::wstring(fd.cFileName);
            fn = std::string(fn_ws.begin(), fn_ws.end());
            printf("[%s][file]:%s\n", __func__, fn.c_str());
        }
        else {
            fn_ws = std::wstring(fd.cFileName);
            fn = std::string(fn_ws.begin(), fn_ws.end());
            printf("[%s][unspecified attribute file]:%s\n", __func__, fn.c_str());
        }
    }
    FindClose(hFind);
    return;
}

You can have a main.cpp like:

int main() {
    std::string dir_name("C:\\test");
    iterate_dir(dir);
    return 0;
}

Upvotes: 0

skyzip
skyzip

Reputation: 255

If you are just looking for methods, maybe this will help a bit: https://www.geeksforgeeks.org/c-program-list-files-sub-directories-directory/ (just copy-pasted the code in case)

Tested it on linux machine and it seems to work. Not recursive though.

int main(void) 
{ 
        struct dirent *de; /* Pointer for directory entry */

        /* opendir() returns a pointer of DIR type. */ 
        DIR *dr = opendir("."); 

        if (dr == NULL) /* opendir returns NULL if couldn't open directory */
        { 
                printf("Could not open current directory" ); 
                return 0; 
        } 

        /* Refer http://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html 
          for readdir() */
        while ((de = readdir(dr)) != NULL) 
                        printf("%s\n", de->d_name); 

        closedir(dr);    
        return 0; 
}

Also, see this question if you need to check if a listed file is a directory: Checking if a dir. entry returned by readdir is a directory, link or file

This method may not be as portable as it seems, but worth a try.

Cheers!

Upvotes: 1

Related Questions