Reading a Directory

I’m refusing to call it a “folder.” That nonsense gained popularity with the Macintosh and then Windows. Before then, it was a directory, a list of files stored on media. Special C language functions are available to read and manipulate directories, which helps your programs manage files and do other fun file stuff.

A directory is really a special type of file, a data container that acts as a database referencing other files stored on the media. The media’s file system determines how the files are organized and accessed. The directory holds all that information, such as the file’s physical location, its name, timestamps, permissions, and other trivia. These details are accessible when you use the proper C language functions.

To access a directory, use the opendir() function. It’s prototyped in the dirent.h header file as:

DIR *opendir(const char *filename);

The function requires a string argument, a name or path to a directory. The value returned is a DIR pointer, similar to the FILE pointer returned by fopen().

After opening the directory and doing whatever, you use the closedir() function to close the directory:

int closedir(DIR *dirp);

The function requires a DIR pointer (dirp, heh) and returns 0 upon success, otherwise -1. Use the errno global variable to further examine the issue when -1 is returned.

In the following code, the current directory (abbreviated as . ) is opened and closed:

#include <stdio.h>
#include <dirent.h>

int main()
{
    DIR *folder;

    folder = opendir(".");
    if(folder == NULL)
    {
        puts("Unable to read directory");
        return(1);
    }
    else
    {
        puts("Directory is opened!");
    }
    closedir(folder);

    return(0);
}

The DIR pointer variable folder acts as the directory handle for the opendir() function in Line 8. If it’s NULL, the program quits. Otherwise a simple string is output and the directory is closed in Line 18. Here’s sample output:

Directory is opened!

Opening and closing a directory is boring, but I like to build upon code when presenting a new concept. To expand the program and make it useful, the readdir() function is added. Here’s how it’s prototyped, also in the dirent.h header file:

struct dirent *readdir(DIR *dirp);

Structure variable dirent is a pointer that contains information about a specific entry read from a directory, referenced by the DIR pointer used in the readdir() function. This function is called repeatedly until NULL is returned, indicating no further entries are available in the directory.

The dirent structure is customized based on the file system. A key member worthy of access is d_name, which represent the directory entry’s filename. The following code demonstrates how the d_name structure member can be used when reading a directory:

#include <stdio.h>
#include <dirent.h>

int main()
{
    DIR *folder;
    struct dirent *entry;
    int files = 0;

    folder = opendir(".");
    if(folder == NULL)
    {
        perror("Unable to read directory");
        return(1);
    }

    while( (entry=readdir(folder)) )
    {
        files++;
        printf("File %3d: %s\n",
                files,
                entry->d_name
              );
    }

    closedir(folder);

    return(0);
}

This code is the same as the previous example, with a while loop inserted to read the directory entries. The loop spins as long as the value returned from readdir() isn’t NULL. For each item found, int variable files tracks its sequential number (which is part of this code and not part of the file system) and entry->d_name prints its name:

File   1: .
File   2: ..
File   3: 0825a.c
File   4: 0825b.c
File   5: 08exercise-a.c
File   6: 08exercise-b.c
File   7: 0901.c
File   8: 0908.c
File   9: a.out
File  10: gettysburg.txt
File  11: sto

Directory entries . and .. represent the current and parent directories. The other items are files, though I know that sto is another directory. In next week’s Lesson, I discuss how to differentiate between standard files and directory entries.

Leave a Reply