This item was added on: 2003/02/27
To access a directory, and the files within it, is a very compiler/OS specific task. It's not practicable to show how to do this for all variations, so here are some examples for various compilers.
The basic principle is the same for each, start by attaching to the base directory, and then the first file within it. Then repeatedly ask for the "next" file, if it's a directory, move into it, and start over. Recursion is used to achieve this, and this code provides a good example of that technique which is nice to follow through.
This first example, adapted from a post by Salem, if I remember correctly, works on Borland 5.5 command line compiler (and possibly other versions). It simply performs a recursive search of all directories on the current drive, looking for files matching the name provided by the user. The filename comparison function uses strcmp()
, which is case sensitive, so watch out for that if you use this code.
Instead of printing each matching file, the walker()
function could be adapted to take a function pointer as an argument, and then call that function for each matching file. This would make the code more versatile, but naturally, it's up to you what you do with it.
#include <stdio.h>
#include <dir.h>
#include <string.h>
#define ALL_ATTS (FA_DIREC | FA_ARCH)
void walker(const char *, const char *);
void walker(const char *path, const char *findme)
{
struct ffblk finder;
unsigned int res;
chdir(path);
for (res = findfirst("*.*", &finder, ALL_ATTS); res == 0; res = findnext(&finder))
{
if (strcmp(finder.ff_name, ".") == 0) continue;
if (strcmp(finder.ff_name, "..") == 0) continue;
if (finder.ff_attrib & FA_DIREC)
{
char newpath[MAXPATH];
strcpy(newpath, path);
strcat(newpath, "\\");
strcat(newpath, finder.ff_name);
chdir(finder.ff_name);
walker(newpath, findme);
chdir("..");
}
else
{
if (strcmp(finder.ff_name, findme) == 0)
{
printf("Found in: %s\n", path);
}
}
}
}
int main(void)
{
const char *root = "\\";
char buf[BUFSIZ];
printf ("This program will find a file on the current drive.\n"
"Enter the name of the file to look for: ");
fflush(stdout);
if (fgets(buf, sizeof(buf), stdin))
{
strtok(buf, "\n");
walker(root, buf);
}
return(0);
}
This next example supplied by vVv was written for the *nix FAQ, so it should be suitable for POSIX compliant compilers/systems. It also compiles on Borland 5.5
#include <dirent.h>
#include <stdio.h>
int main(void)
{
DIR *d;
struct dirent *dir;
d = opendir(".");
if (d)
{
while ((dir = readdir(d)) != NULL)
{
printf("%s\n", dir->d_name);
}
closedir(d);
}
return(0);
}
The following is an expanded example for Unix systems.
#include <dirent.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int walker( char *searching, char *result ) {
DIR *d;
struct dirent *dir;
d = opendir( "." );
if( d == NULL ) {
return 1;
}
while( ( dir = readdir( d ) ) ) {
if( strcmp( dir->d_name, "." ) == 0 ||
strcmp( dir->d_name, ".." ) == 0 ) {
continue;
}
if( dir->d_type == DT_DIR ) {
chdir( dir->d_name );
walker( searching, result );
chdir( ".." );
} else {
if( strcmp( dir->d_name, searching ) == 0 ) {
int len;
getcwd( result, MAXPATHLEN );
len = strlen( result );
snprintf( result + len, MAXPATHLEN - len, "/%s", dir->d_name );
break;
}
}
}
closedir( d );
return *result == 0;
}
int main( ) {
char buf[MAXPATHLEN] = { 0 };
if( walker( "lame", buf ) == 0 ) {
printf( "Found: %s\n", buf );
} else {
puts( "Not found" );
}
return 0;
}
And now a Win32 example
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
void errormessage(void)
{
LPVOID lpMsgBuf;
FormatMessage
(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) & lpMsgBuf,
0,
NULL
);
fprintf(stderr, "%s\n", (char*)lpMsgBuf);
LocalFree(lpMsgBuf);
}
void format_time(FILETIME *t, char *buff)
{
FILETIME localtime;
SYSTEMTIME sysloc_time;
FileTimeToLocalFileTime(t, &localtime);
FileTimeToSystemTime(&localtime, &sysloc_time);
sprintf
(
buff,
"%4d/%02d/%02d %02d:%02d:%02d",
sysloc_time.wYear,
sysloc_time.wMonth,
sysloc_time.wDay,
sysloc_time.wHour,
sysloc_time.wMinute,
sysloc_time.wSecond
);
}
void format_attr(DWORD attr, char *buff)
{
*buff++ = attr & FILE_ATTRIBUTE_ARCHIVE ? 'A' : '-';
*buff++ = attr & FILE_ATTRIBUTE_SYSTEM ? 'S' : '-';
*buff++ = attr & FILE_ATTRIBUTE_HIDDEN ? 'H' : '-';
*buff++ = attr & FILE_ATTRIBUTE_READONLY ? 'R' : '-';
*buff++ = attr & FILE_ATTRIBUTE_DIRECTORY ? 'D' : '-';
*buff++ = attr & FILE_ATTRIBUTE_ENCRYPTED ? 'E' : '-';
*buff++ = attr & FILE_ATTRIBUTE_COMPRESSED ? 'C' : '-';
*buff = '\0';
}
struct flist
{
int num_entries;
int max_entries;
WIN32_FIND_DATA *files;
};
void addfile(flist *list, WIN32_FIND_DATA data)
{
if (list->num_entries == list->max_entries)
{
int newsize = list->max_entries == 0 ? 16 : list->max_entries * 2;
WIN32_FIND_DATA *temp = (WIN32_FIND_DATA *) realloc(list->files, newsize * sizeof(WIN32_FIND_DATA));
if (temp == NULL)
{
fprintf(stderr, "Out of memory\n");
exit(1);
}
else
{
list->max_entries = newsize;
list->files = temp;
}
}
list->files[list->num_entries++] = data;
}
int sortfiles(const void *a, const void *b)
{
const WIN32_FIND_DATA *pa = (WIN32_FIND_DATA *) a;
const WIN32_FIND_DATA *pb = (WIN32_FIND_DATA *) b;
int a_is_dir = pa->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
int b_is_dir = pb->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
if (a_is_dir ^ b_is_dir)
{
if (a_is_dir) return(-1);
if (b_is_dir) return(+1);
return(0);
}
else
{
return(strcmp(pa->cFileName, pb->cFileName));
}
}
void doit(char *root)
{
flist list = { 0, 0, NULL };
HANDLE h;
WIN32_FIND_DATA info;
int i;
h = FindFirstFile("*.*", &info);
if (h != INVALID_HANDLE_VALUE)
{
do
{
if (!(strcmp(info.cFileName, ".") == 0 || strcmp(info.cFileName, "..") == 0))
{
addfile(&list, info);
}
} while (FindNextFile(h, &info));
if (GetLastError() != ERROR_NO_MORE_FILES) errormessage();
FindClose(h);
}
else
{
errormessage();
}
qsort(list.files, list.num_entries, sizeof(list.files[0]), sortfiles);
int numdirs = 0;
for (i = 0; i < list.num_entries; i++)
{
char t1[50], t2[50], t3[50], a[10];
format_time(&list.files[i].ftCreationTime, t1);
format_time(&list.files[i].ftLastAccessTime, t2);
format_time(&list.files[i].ftLastWriteTime, t3);
format_attr(list.files[i].dwFileAttributes, a);
if (list.files[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
sprintf(t2, "%4d/%02d/%02d %02d:%02d:%02d", 2000, 1, 1, 0, 0, 0);
}
printf("%s %10ld %s %s %s %s\\%s\n", a, list.files[i].nFileSizeLow, t1, t2, t3, root, list.files[i].cFileName);
if (list.files[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) numdirs++;
}
list.files = (WIN32_FIND_DATA *) realloc(list.files, numdirs * sizeof(WIN32_FIND_DATA));
for (i = 0; i < numdirs; i++)
{
char newroot[MAX_PATH];
sprintf(newroot, "%s\\%s", root, list.files[i].cFileName);
SetCurrentDirectory(list.files[i].cFileName);
doit(newroot);
SetCurrentDirectory("..");
}
free(list.files);
}
void banner(void)
{
printf("Attribs ");
printf(" Size ");
printf(" CreationTime ");
printf(" LastAccessTime ");
printf(" LastWriteTime ");
printf("Filename\n");
}
int main(int argc, char *argv[])
{
if (argc > 1)
{
char olddir[MAX_PATH];
if (GetCurrentDirectory(MAX_PATH, olddir) == 0)
{
errormessage();
exit(1);
}
if (!SetCurrentDirectory(argv[1]))
{
errormessage();
exit(1);
}
banner();
doit(".");
SetCurrentDirectory(olddir);
}
else
{
banner();
doit(".");
}
return(0);
}
Credit: Salem, vVv and Hammer