Hi,

I have been experiment with Recursion / Trasversal through directories recently but seem to have run into a few unexplainable errors. Attached is my source code which is a function (which has the path (input user directory) passed into it).

What im hoping this function will do is detect if inside this directory (path) are subdirectories and if so store these in an array (creating a list of subdirectories) allowing a following function to open these inorder and run a process on all files inside.

Any ideas what im doing wrong? I've look across various forums etc at FindNextFile(), FindNext() functions etc but have been unable to get my head around them.

Many thanks;

void DirectoryCheck(char path[50])
{
     
  int dirno2;  //used to count directories once i get the function working
  dirno2 = 0;
     
  chdir (path);
     printf (path);
  
  char directories[15][50];
     
  //void EmptyDirectory(char* folderPath)

 char fileFound[256];
 WIN32_FIND_DATA info;
 HANDLE hp; 
 printf(fileFound, " %s\\*.*", path);
 hp = FindFirstFile(fileFound, &info);
 printf("\n");
 
 do
    {
        if (!((strcmp(info.cFileName, ".")==0)||
              (strcmp(info.cFileName, "..")==0)))
        {
          if((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)== 0)
          {
              printf("Sub Directory File Found : ");
              printf(fileFound,"%s\\%s", path, info.cFileName);
              printf("done top\n");
           }
         
         
          else
          {
              printf("Text File Found : ");
              printf("%s\\%s", folderPath, info.cFileName);
          }
        }
 
    }while(FindNextFile(hp, &info)); 
 FindClose(hp);
}

You say you're doing it recursively, but it looks iterative to me.

Here's a pseudocode example of what you want to do.

global list L; /* To store the pathnames. */
DirectoryCheck( D ):
    L.add_path( D )
    for each subdirectory S in D:
        DirectoryCheck(S)

So in your code, where you print 'subdirectory file found', you should run DirectoryCheck on the new path you discovered.

Unfortunately, I don't know the usage of Windows' FileNext family of functions, so I can't help there, and I can't compile it myself to see what your unexplainable errors are. Hopefully this helps out.

This is a lot of information that although old, is still used by Windows (up to XP that I'm sure of).

Also, there is a short example program, using findfirst and findnext.

/* This is from Turbo C/C++ (the C compiler), ver. 1.01 Help

findfirst: Searches a disk directory.
findnext: Continues findfirst search.

Syntax:
int findfirst(const char *pathname, struct ffblk *ffblk, int attrib);
int findnext(struct ffblk *ffblk);

Prototype in:
dir.h

Remarks:
findfirst begins a search of a disk directory by using the DOS system call
0x4E.

pathname is a string with an optional drive specifier, path, and file name
of the file to be found.

The file name portion can contain wildcard match characters (such as ? or
*).

If a matching file is found, the ffblk structure is filled with the
file-directory information.

The format of the structure ffblk is as follows:

struct ffblk {
char ff_reserved[21]; /* reserved by DOS */
char ff_attrib; /* attribute found */
int ff_ftime; /* file time */
int ff_fdate; /* file date */
long ff_fsize; /* file size */
char ff_name[13]; /* found file name */
};

attrib is a DOS file-attribute byte used in selecting eligible files for the
search.

attrib can be one of the following constants defined in dos.h:

Constant ³ Description
=====================================
FA_RDONLY ³ Read-only attribute
FA_HIDDEN ³ Hidden file
FA_SYSTEM ³ System file
FA_LABEL ³ Volume label
FA_DIREC ³ Directory
FA_ARCH ³ Archive

For more detailed information about these attributes, refer to your DOS
reference manuals.

ff_ftime and ff_fdate contain bit fields for referring to the current date
and time. The structure of these fields was established by MS-DOS. ff_ftime
and ff_fdate are 16-bit structures divided into three fields, as shown in
the following tables.

Bits ³ Description
===================================
ff_ftime³
0-4 ³ The result of seconds divided by 2 (for example, 10 here
³ means 20 seconds)
5-10 ³ Minutes
11-15 ³ Hours
ff_fdate³
0-4 ³ Day
5-8 ³ Month
9-15 ³ Years since 1980 (for example, 9 here means 1989)

The structure ftime declared in io.h uses time and date bit fields similar
in structure to ff_ftime, and ff_fdate.

See getftime or setftime for examples.

findnext is used to fetch subsequent files that match the pathname given in
findfirst.

ffblk is the same block filled in by the findfirst call. This block contains
necessary information for continuing the search.

One file name for each call to findnext will be returned until no more files
are found in the directory matching the pathname.

Return Value:
findfirst and findnext returns 0 on successfully finding a file matching the
search pathname.

When findfirst and findnext can find no more files, or if there is some
error in the file name, -1 is returned, and the global variable errno is set
to one of the following:

Setting³ Description
=========================
ENOENT ³ Path or file name not found
EMFILE ³ No more files

Portability:
findfirst and findnext are unique to DOS.

Example:
findnext example
*/

#include <stdio.h>
#include <dir.h>

int main(void)
{
   struct ffblk ffblk;
   int done;
   printf("Directory listing of *.*\n");
   done = findfirst("*.*",&ffblk,0);
   while (!done)
   {
      printf("  %s\n", ffblk.ff_name);
      done = findnext(&ffblk);
   }
   done = getchar();
   return 0;
}

This is from Turbo C - very old, but still works with WindowsME, 2000, and XP on NTFS formatted drives, flash drives, etc.

It is a lot to take in. In the meantime, why don't you get the example program from the MSDN Library, and use it?

You say you're doing it recursively, but it looks iterative to me.

Here's a pseudocode example of what you want to do.

global list L; /* To store the pathnames. */
DirectoryCheck( D ):
    L.add_path( D )
    for each subdirectory S in D:
        DirectoryCheck(S)

So in your code, where you print 'subdirectory file found', you should run DirectoryCheck on the new path you discovered.

Unfortunately, I don't know the usage of Windows' FileNext family of functions, so I can't help there, and I can't compile it myself to see what your unexplainable errors are. Hopefully this helps out.

Just wanted to say thank you for your help, the pseudo code has better helped me visualise the structure i need from the function, hopefully with the other replies I can put it together and will post the code. Thanks again

Wow thats a lot of information lol. Thank you for providing it and for the example code.

I was hoping that there was a simple way I could use the FILE_ATTRIBUTES so that if the file found is a folder / subdirectory then it would just copy its name so I can chdir into it at a later time.

I'll try and use the information provided to do this and submit any code I work out, Thank you again :-)

See this code snippet I posted here about 5 years ago.

Hi thank you for the code snippet,

I need to keep the code in a C file format rather than extending to C++ (although I agree it would be a much easier option). I wonder if I can take the idea and transform it back in to C though ...


Cheers

The idea for what you want to do is the same in both c and c++. If you are calling FindFirstFile() and FindNextFile(), just check the dwFileAttributes member of the WIN32_FIND_DATA structure to see if the file is a folder -- FILE_ATTRIBUTE_DIRECTORY. If it is, then do recursive call to the function like I wrote in that code snippet.

The idea for what you want to do is the same in both c and c++. If you are calling FindFirstFile() and FindNextFile(), just check the dwFileAttributes member of the WIN32_FIND_DATA structure to see if the file is a folder -- FILE_ATTRIBUTE_DIRECTORY. If it is, then do recursive call to the function like I wrote in that code snippet.

Isnt this what I tried to do with;

If ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
        printf("sub directory found \n");
}

Thanks

That's wrong. Remove the "== 0" part. See line 32 of the code snippet I wrote.

If ( info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
        printf("sub directory found \n");
}

Interesting, it doesnt seem to work on mine, there must be a problem with the loop or something. When I try to output the name of the file found as a directory it outputs nothing and wont keep looping.

It must be something I doing wrong, I think I'll need to re-review it and try other ideas too, will post code if I get it working, thank you

void DirectoryCheck(char path[50])
{
     
  int dirno2;
  dirno2 = 0;
     
  chdir (path);
     printf (path);
  
  char directories[15][50];
     
  //void EmptyDirectory(char* folderPath)




 char fileFound[256];
 WIN32_FIND_DATA info;
 HANDLE hp; 
 //printf("declare at top\n");
 printf(fileFound, " %s\\*.*", path);
 hp = FindFirstFile(fileFound, &info);
 printf("\n");
 
 do
    {
              
        if (!((strcmp(info.cFileName, ".")==0)||
              (strcmp(info.cFileName, "..")==0)))
        {
          if(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
          {
              printf("Sub Directory File Found : ");
              printf(fileFound,"%s\\%s", path, info.cFileName);
 
          }
         else
{
          printf("file found! :");
          printf(fileFound,"%s\\%s", path, info.cFileName);
}
         
        }
}
    while(FindNextFile(hp, &info)); 
 FindClose(hp);
}

line 21 should be sprintf(), not printf()

Tried that the output I get is:

"
C:\
Sub Directory File Found : C:\\á."

"

or if path is set as C:\Test which has a folder called Empty in it:

"

C:\Test
Sub Directory File Found : C:\Test\\á."


"

Please note in both cases the '.' is between the top and bottom of the line.
Its worth noting that it only ever displays 1 sub directory found even if more than one file is in existence of the source directory.

Any Ideas? Many thanks

Try posting a complete example with all the print / sprintf issues fixed.

Reconstructing your bugs from what you've posted is too hard.

CHECK all your printf calls, most of them seem to be broken.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.