Crossing Between Formatted and Unformatted File Functions

One of the reasons behind the low-level open() function is to access non-traditional files. This stems from the UNIX environment’s treatment of every device as a file. Sometimes you need low-level access to accomplish specific tasks, such as accessing a device driver. Yet, in the C language universe, an interesting crossover is provided between low-level raw file access and formatted file access.

The function that bridges the gap is fdopen(). Here is its format:

FILE * fdopen(int fildes, const char *mode);

This function works like the fopen() function, but substituting a file descriptor integer, fildes, for the filename (first) argument. The fildes is the integer value returned from an open() function. The second argument is a string representing the file-opening mode. The value returned is a FILE pointer.

After the fdopen() function is successfully used on a file opened by using the open() function, you can use employ the familiar formatted file functions to work with the file. When you’re done, you first fclose() the file that fdopen() opened, then close() the file the open() function opened. Yes, the process involves more overhead, but that’s how it works. Sample code:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    const char filename[] = "gettysburg.txt";
    FILE *fp;
    int fdes,ch;

    /* open the file to get a file descriptor */
    fdes = open(filename,O_RDONLY);
    if( fdes==-1 )
    {
        fprintf(stderr,"Unable to open %s for unformatted input\n",filename);
        exit(1);
    }

    /* use the descriptor to open the file for streamed input */
    fp = fdopen(fdes,"r");
    if( fp==NULL )
    {
        fprintf(stderr,"Unable to open %s for streamed input\n",filename);
        exit(1);
    }

    /* read the file using formatted input */
    while( !feof(fp) )
    {
        ch = fgetc(fp);
        if( ch==EOF )
            break;
        putchar(ch);
    }

    /* close the open files */
    fclose(fp);
    close(fdes);

    return(0);
}

The code first uses the open() function at Line 13 to open gettysburg.txt. The file descriptor is stored in int variable fdes.

Next, the fdopen() function opens the file, already open for unformatted reading, for formatted reading:

fp = fdopen(fdes,"r");

The fdes variable is used instead of a filename. The result is saved in the fp FILE pointer, which is immediately tested. If everything is kosher, the fgetc() function reads the file’s contents and outputs its text:

while( !feof(fp) )
{
    ch = fgetc(fp);
    if( ch==EOF )
        break;
    putchar(ch);
}

The feof() function and a test for the EOF character are used to determine when all the text is read from the file. These are formatted file-reading techniques, yet applied to a file originally opened for low-level access.

Two statements are required to close-up when done:

fclose(fp);
close(fdes);

A sample run output text from the gettysburg.txt file.

The fdopen() function provides a useful way to use your favorite file access functions on files opened for low-level access. Do be aware that the fdopen() function must be used in the same mode as the file was opened with in the open() function. Further, some file-opening mode strings don’t work on files opened in-the-raw: The "x" mode causes fdopen() to fail if the file opened doesn’t exist.

Leave a Reply