. .
. .
. .
.

Logging a directory, part 1.

Dir Command.

Okay, so for whatever reason you have in mind, your program needs to know what files are in a certain directory, how do you do that? You'll be glad to know it is easy! There are a couple of Win32 API routines that will give you what you want, FindFirstFile() and FindNextFile().

First, why two routines? Well, the API designers could have created a routine which returned an array of strings, but consider their problem, there could be hundreds of thousands of files, each with tens of characters in their name. The memory structure necessary to hold that lot would be huge!

It gets worse! The filename is only one of the things Windows stores for each file. It also holds the creation date, the last modified date, it's size etc. It is entirely possible that a big directory containing files with long names, when all the ancilliary data is also included, could require more memory than the process is allowed.

The solution chosen was to have an initial routine which basically takes a snapshot of the directory, and returns the information about the first file it found. You then call the second routine again and again, each time, the second routine returns the information about the "next" file in the directory, until there are no more. There is actually a third routine we'll need to use, but more about that later.

Let's have a look at the first two. The prototypes for them from MSDN are shown here...

HANDLE FindFirstFile(LPCTSTR lpFileName,
                     LPWIN32_FIND_DATA lpFindFileData);

...and...

BOOL FindNextFile(HANDLE hFindFile,
                  LPWIN32_FIND_DATA lpFindFileData);

... so let's see how to get them to do something useful.

We start with FindFirstFile(). The first parameter is the name of the file to search for, this can of course, take the normal Windows wildcard characters. The other parameter is a pointer to a WIN32_FIND_DATA structure, this is the memory structure that Windows will fill in for you with all the data about the file. It is described like this...

typedef struct _WIN32_FIND_DATA {
    DWORD dwFileAttributes; 
    FILETIME ftCreationTime; 
    FILETIME ftLastAccessTime; 
    FILETIME ftLastWriteTime; 
    DWORD    nFileSizeHigh; 
    DWORD    nFileSizeLow; 
    DWORD    dwReserved0; 
    DWORD    dwReserved1; 
    TCHAR    cFileName[ MAX_PATH ]; 
    TCHAR    cAlternateFileName[ 14 ]; 
} WIN32_FIND_DATA; 

... there are fields for attributes, (the commonest is probably "Read Only" but there are several others), FILETIME structures for Create/Accessed/Modified date/times, fields which hold the file size, (more about that later), some place holders for future expansion, (ignore these), and the two filenames, the real filename, and the old fashioned "8.3" filename.

If no errors occur, FindFirstFile() returns a Search Handle, this is used as context for the search. Context, what does that mean? Consider this application. Suppose you want to see if the same file exists in two directories, you call FindFirstFile() with the search string pointing at one directory, then again with the second directory, if the first file in the second directory is not a match, you'd want to try the next file in the second directory, so you call FindNextFile(), but how does the system know you want the next file in the second directory, you could be asking for the next file in the first! This is what the search handle is for, you pass the search handle that is returned by the call to FindFirstFile() to FindNextFile(), now the system knows which one you want, the search handle links a call to FindNextFile() with a call to FindFirstFile().

The search handle is the first parameter to the FindNextFile() routine, the second is, again, a pointer to a WIN32_FIND_DATA structure. FindNextFile() returns TRUE if there is another file to return, and there are no errors.

Above, I mentioned a third routine we will use, this is FindClose(). When you have finished logging the directory, you use FindClose() to close the search handle, telling the system that you are finished with this particular search operation. The prototype for FindClose() is shown here...

BOOL FindClose(
  HANDLE hFindFile
);

... very simple.

Given what we have got so far, we can write a very simple program which will list the files in a directory to the screen. Here is such a program...

#include <windows.h> 
#include <iostream> 
using namespace std;

int main()
{
    HANDLE hFind;
    WIN32_FIND_DATA FindData;

    cout << "A very basic FindFirst/Next demo.\n" << endl;

// Find the first file

    hFind = FindFirstFile("C:\\Windows\\*.exe", &FindData);
    cout << FindData.cFileName << endl;

// Look for more

    while (FindNextFile(hFind, &FindData))
    {
        cout << FindData.cFileName << endl;
    }

// Close the file handle

    FindClose(hFind);

    return 0;
}

... here I have hard coded the search path to search for all the .exe files in my Windows directory. When I ran this on my machine, the result looked like this...

Program Output.

... so there we have a very basic file logger. There is actually more to this if you want to be correct, what happens for example, if there are no files that match? We'll look a bit more closely at this and other potential problems in the next section.


.
. .
.
Previous Index Next Page
Site Home
.
. .
Copyright © adrianxw, 1997 - 2003.