Understanding File Descriptor and File Pointer

Discussion in 'C' started by Trinity, Aug 25, 2012.

  1. Trinity

    Trinity New Member

    Joined:
    Nov 23, 2011
    Messages:
    28
    Likes Received:
    11
    Trophy Points:
    3
    Occupation:
    Software Engineer
    During C programming, file operations are pretty common. And when you are writing programs in C on Linux, two familiar terms related to file operations are File Pointers and File Descriptors.

    We know both are different, but what are they? This article will focus on understanding what are file descriptors, file pointers and how are they related at the kernel level.

    Understanding individually



    File Descriptor is an integer value at the kernel level which identifies the file to be operated during the program. Here, its worth mentioning, that everything on Linux is a file.

    In C system programming, we have following method to open a file:
    Code:
    int fd = open ("/etc/myfile.txt", O_WRONLY);
    
    This system call returns the file descriptor.

    However, Standard C also provides another method for opening a file,
    Code:
    FILE *fp = fopen ("/etc/myfile.txt", "w");
    
    This C library method returns a file pointer.

    File Pointer is a pointer to a C structure, identifying a file, wrapping the file descriptor, buffering functionality and all other functionality needed for I/O operation.

    The file pointer is of type FILE, whose definition can be found in "/usr/include/stdio.h". This definition may vary from one compiler to another.

    Here is one such definition:
    Code:
    typedef struct {
            unsigned char   *_ptr;
            int     _cnt;
            unsigned char   *_base;
            unsigned char   *_bufendp;
            short   _flag;
            short   _file;
            int     __stdioid;
            char    *__newbase;
    #ifdef _THREAD_SAFE
            void *_lock;
    #else
            long    _unused[1];
    #endif
    #ifdef __64BIT__
            long    _unused1[4];
    #endif /* __64BIT__ */
    } FILE;
    
    Hence, talking about differences between a file pointer and a file descriptor,
    • File Pointer includes various I/O functionality like buffering, EOF detection, etc whereas File Descriptor does not.
    • File Pointer is the most widely used and standardized, however, File Descriptor is a low level kernel variable and limited to Linux.

    Deeper Understanding - At the Kernel level



    The Kernel maintains a Kernel File Table for every open file by any process. Each entry in this kernel file table is identified by our File Descriptor. Hence, any file opened by any process would have a file descriptor and that file would have its entry maintained in the kernel file table until it is closed. Another interesting fact is, even if the same file on the disk is opened by two different processes, they would have their own separate file table entries in the kernel file table with separate file descriptor values. This is needed to store the mode of open, current file position, etc for each opened instance of the file.

    Generally, an entry in the kernel file table would consist of:
    • File Descriptor
    • Current File Position
    • inode info
    • vnode info
    • file metadata
    • etc
    However, every process also has its own File Descriptor (FD) table, which is basically a data structure identifying the opened file instance and includes a pointer to the entry in the kernel file table. Each entry in this FD table is of the opened file in the process.

    At the userspace level, the file pointer is used to read/write onto a file. Whereas, at the system level, it uses the lower level variable file descriptor.
    Here is an abstract illustration:

    [​IMG]

    So, when we write the code
    Code:
    1. File *fp;
    2. fp = fopen ("/etc/myfile.txt", "w");
    3. fclose(fp);
    
    In statement 1, a 4 byte memory for the pointer is created of type 'FILE' on stack.
    In statement 2, a memory = 'sizeof(FILE)' is allocated on heap, and address of which is assigned to the pointer 'fp'.
    Along with, a new entry created in the FD table of the process followed by, an entry created in the kernel file table representing the newly opened file instance having a unique FD.

    During the read/write/other IO operations, values are maintained by the Kernel File Table entry.

    In statement 3, all the allocated memory for file pointer is released and the entry is deleted.

    File Pointer from File Descriptor



    Use method
    Code:
    FILE * fdopen (int fd, const char *mode);
    
    The header file is "stdio.h"

    Example:
    Code:
    #include <stdio.h>
    #include <fcntl.h>
    
    int main()
    {
        int fd;
        FILE *fp;
        fd = open ("myfile.txt", O_WRONLY | O_APPEND| O_CREAT);
        if (fd < 0)
        {
            printf("Error opening file through FD\n");
            exit (1);
        }
        write (fd, "Writing using FD\n", 17);
    
        fp = fdopen(fd, "a");
        fprintf(fp, "Writing using File Ptr\n");
        fclose (fp);
        close(fd);
    
        return 0;
    }
    
    Here is the Output:
    Code:
    [fedora@fedora16 fdfptr]$ sudo cat myfile.txt 
    Writing using FD
    Writing using File Ptr
    

    File Descriptor from File Pointer


    Code:
    int fileno(FILE * fp);
    
    The header file is again "stdio.h".

    Example:
    Code:
    #include <stdio.h>
    #include <fcntl.h>
    
    int main()
    {
        int fd;
        FILE *fp;
        fp = fopen ("myfile.txt", "a+");
        if (fp == NULL)
        {
            printf("Error opening file through FP\n");
            exit (1);
        }
        fprintf(fp, "Writing using File Ptr\n");
    
        fd = fileno (fp);
        write (fd, "Writing using FD\n", 17);
    
        fclose (fp);
        close(fd);
    
        return 0;
    }
    
    
    Here is the Output:
    Code:
    [fedora@fedora16 fdfptr]$ sudo cat myfile.txt 
    Writing using FD
    Writing using File Ptr
    

    Conclusion



    Now we know what internally file descriptor and file pointer is, and how they work in their respective spaces. Also, we know how to get one from the other. So, keep playing and exploring and share any interesting fact you get across.
     
    Last edited by a moderator: Jan 21, 2017

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice