All Files Have a Number

The common way for humans to describe a file is to use its name. You refer to hello.txt as a file. The fopen() function C uses this nomenclature, which is handy and convenient. While a program runs, however, a file number is assigned to an open file.

The file number is an integer. It’s assigned sequentially, starting with 0. The first three numbers are reserved to the standard I/O devices: stdin, stdout, and stderr. After that, any files you open in a program use a number as a reference.

The number itself is trivial. I’m sure it’s used internally, but within your code you’ll use a FILE variable to reference the file for reading, writing, and eventually closing.

In Unix, you can use the ulimit command in bash determine the maximum allowed number of open files. On my Mac, it’s 256. In Windows, the limit appears to be set by the C runtime library to 512, but that information is inconsistent. Back under DOS, the FILES command in CONFIG.SYS set the maximum number of open files.

To glean the file number for any open file, you use the fileno() function. It’s defined in the stdio.h header and its man page format looks like this:

int fileno(FILE *stream)

The stream represents an open file, or the three standard I/O devices. The value returned is an integer representing the file number.

Here is a sample program that displays the file number values for the standard I/O devices:

#include <stdio.h>

int main()
{
    printf("File number for 'stdin' is %d\n",fileno(stdin));
    printf("File number for 'stdout' is %d\n",fileno(stdout));
    printf("File number for 'stderr' is %d\n",fileno(stderr));

    return(0);
}

Here is the program’s output:

File number for 'stdin' is 0
File number for 'stdout' is 1
File number for 'stderr' is 2

These file numbers are consistent for the three standard I/O devices on all computers at all times. When you open another file, it’s assigned the next highest value, as this code demonstrates:

#include <stdio.h>

int main()
{
    FILE *f;

    f = fopen("hello.txt","w");
    if( f == NULL)
    {
        puts("Error creating file.");
        return(1);
    }
    printf("File number for 'hello.txt' is %d\n",fileno(f));
    fclose(f);

    return(0);
}

Here is sample output:

File number for 'hello.txt' is 3

So what’s the point?

Really, there isn’t any point to a file descriptor outside of the Unix environment. In Windows, the numbers are assigned, but not needed anywhere else.

In Unix, you can use the descriptor with the low-level read() and write() functions. Even so, experienced programmers recommend that you instead use the FILE variable and the standard fopen(), fread(), fwrite(), and similar functions. That leaves the fileno() function a side note. Still, I think it’s interesting that the three standard I/O devices are always open and always assigned the same file number values.

Leave a Reply