Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C (http://www.go4expert.com/articles/c-tutorials/)
-   -   Understanding File Descriptor and File Pointer (http://www.go4expert.com/articles/understanding-file-descriptor-file-t28936/)

Trinity 25Aug2012 06:04

Understanding File Descriptor and File Pointer
 
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:

http://imgs.g4estatic.com/file-descr...lePointers.jpg

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.


All times are GMT +5.5. The time now is 01:35.