How are file descriptors and file pointers related? When is it appropriate to use each?
-
1https://www.gnu.org/software/libc/manual/html_node/Streams-and-File-Descriptors.html – Suraj Jain Dec 14 '19 at 09:50
9 Answers
A file descriptor is a low-level integer "handle" used to identify an opened file (or socket, or whatever) at the kernel level, in Linux and other Unix-like systems.
You pass "naked" file descriptors to actual Unix calls, such as read()
, write()
and so on.
A FILE
pointer is a C standard library-level construct, used to represent a file. The FILE
wraps the file descriptor, and adds buffering and other features to make I/O easier.
You pass FILE
pointers to standard C functions such as fread()
and fwrite()
.

- 391,730
- 64
- 469
- 606
-
@nvl: fildes is surely available to Windows, e.g. http://msdn.microsoft.com/en-us/library/z0kc8e3z%28VS.80%29.aspx – kennytm Mar 11 '10 at 09:16
-
3@unwind What you meant by "naked" file descriptors? The linked reference says that the `fd` is the first argument to `read()`. Why do you call it naked? – Geek Jul 27 '14 at 09:37
-
5@Geek Compared to the standard library's `FILE *` type, the integer file descriptor is "less wrapped", i.e. "naked". – unwind Jul 30 '14 at 16:40
-
While this comment sounds authoritative (and it might very well be), I found Suraj Jain's and Vogeesh HT's comments to be more informative and provided a necessary level of detail not available in the other comments. – Stato Machino Jul 20 '21 at 03:58
One is buffered (FILE *
) and the other is not. In practice, you want to use FILE *
almost always when you are reading from a 'real' file (ie. on the drive), unless you know what you are doing or unless your file is actually a socket or so..
You can get the file descriptor from the FILE *
using fileno()
and you can open a buffered FILE *
from a file descriptor using fdopen()
-
18+1 for pointing out fileno(), the organization of the man pages makes this one tough to find. Same for fdopen(). – BD at Rivenhill Apr 30 '10 at 16:29
A file descriptor is just an integer which you get from the POSIX open()
call. Using the standard C fopen()
you get a FILE
struct back. The FILE
struct contains this file descriptor amongst other things such as end-of-file and error indicator, stream position etc.
So using fopen()
gives you a certain amount of abstraction compared to open()
. In general you should be using fopen()
since that is more portable and you can use all the other standard C functions that uses the FILE
struct, i.e., fprintf()
and family.
There are no performance issues using either.

- 15,171
- 8
- 38
- 76

- 19,662
- 12
- 82
- 106
-
12+1 for bringing up portability. FILE is part of the Standard C Library (back to C89/C90); file descriptors are not. – tomlogic Mar 11 '10 at 17:42
File descriptor vs File pointer
File descriptor:
File Descriptor is an integer value returned by open()
system call.
int fd = open (filePath, mode);
- Low/Kernel level handler.
- passe to read() and write() of UNIX System Calls.
- Doesn't include buffering and such features.
- Less portable and lacks efficiency.
File pointer:
File Pointer is a pointer to a C structure returned by fopen()
library function, which is used to 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.
FILE *fp = fopen (filePath, mode);
// A FILE Structure returned by fopen
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;
- It is high level interface.
- Passed to fread() and fwrite() functions.
- Includes buffering,error indication and EOF detection,etc.
- Provides higher portability and efficiency.

- 2,777
- 21
- 18
-
1Are you able to back up that higher efficiency claim? I've never heard that. – Gid Oct 14 '16 at 04:50
-
1The "efficiency" claim could be because of buffering. With a file descriptor, every read() or write() is a syscall, and every syscall should be thought of as expensive. With a FILE*, buffering means some reads and writes won't be syscalls. – Mike Spear Jul 17 '18 at 02:37
Want to add points which might be useful.
ABOUT FILE *
- can't be used for interprocess communication(IPC).
- use it when you need genral purpose buffered I/O.(printf,frpintf,snprintf,scanf)
I use it many times for debug logs. example,
FILE *fp; fp = fopen("debug.txt","a"); fprintf(fp,"I have reached till this point"); fclose(fp);
ABOUT FILE DESCRIPTOR
It's generally used for IPC.
Gives low-level control to files on *nix systems.(devices,files,sockets,etc), hence more powerfull than the
FILE *
.

- 954
- 1
- 12
- 28
-
Can't you use `fdopen()` to do things like IPC and devices with `FILE*`? – osvein Mar 21 '17 at 13:47
-
1Actually, both yes and no. You can't setup and initialize IPC with `FILE*`, but you can create a `FILE*` from a file descriptor (`fdopen()`) and later closing the `FILE` will close the descriptor also. Therefore, you can *do* IPC, but you have to deal with file descriptors a little bit to facilitate any direct IPC. – Micah W Jan 10 '18 at 22:55
Just a note to finish out the discussion (if interested)....
fopen
can be insecure, and you should probably use fopen_s
or open
with exclusive bits set. C1X is offering x
modes, so you can fopen
with modes "rx"
, "wx"
, etc.
If you use open
, you might consider open(..., O_EXCL | O_RDONLY,... )
or open(..., O_CREAT | O_EXCL | O_WRONLY,... )
.
See, for example, Do not make assumptions about fopen() and file creation.

- 97,681
- 90
- 411
- 885
-
As `fopen_s` doesn't seem to be available with `POSIX`, I assume the most portable soultion would be to `open(2)` and then `fdopen(2)`. (leaving windows aside). Also, what would be faster `fopen_s()` or `open(2)` followed by `fdopen(2)`? – Mihir Luthra Aug 10 '19 at 18:08
FILE *
is more useful when you work with text files and user input/output, because it allows you to use API functions like sprintf()
, sscanf()
, fgets()
, feof()
etc.
File descriptor API is low-level, so it allows to work with sockets, pipes, memory-mapped files (and regular files, of course).

- 34,062
- 14
- 56
- 86
-
1+1 because you added memory-mapped files, since as of my current reading, the other answers have been supplied already. – ernie.cordell Feb 28 '14 at 16:17
I found a good resource here, giving high level overview of differences between the two:
When you want to do input or output to a file, you have a choice of two basic mechanisms for representing the connection between your program and the file: file descriptors and streams. File descriptors are represented as objects of type int, while streams are represented as FILE * objects.
File descriptors provide a primitive, low-level interface to input and output operations. Both file descriptors and streams can represent a connection to a device (such as a terminal), or a pipe or socket for communicating with another process, as well as a normal file. But, if you want to do control operations that are specific to a particular kind of device, you must use a file descriptor; there are no facilities to use streams in this way. You must also use file descriptors if your program needs to do input or output in special modes, such as nonblocking (or polled) input (see File Status Flags).
Streams provide a higher-level interface, layered on top of the primitive file descriptor facilities. The stream interface treats all kinds of files pretty much alike—the sole exception being the three styles of buffering that you can choose (see Stream Buffering).
The main advantage of using the stream interface is that the set of functions for performing actual input and output operations (as opposed to control operations) on streams is much richer and more powerful than the corresponding facilities for file descriptors. The file descriptor interface provides only simple functions for transferring blocks of characters, but the stream interface also provides powerful formatted input and output functions (printf and scanf) as well as functions for character- and line-oriented input and output.
Since streams are implemented in terms of file descriptors, you can extract the file descriptor from a stream and perform low-level operations directly on the file descriptor. You can also initially open a connection as a file descriptor and then make a stream associated with that file descriptor.
In general, you should stick with using streams rather than file descriptors, unless there is some specific operation you want to do that can only be done on a file descriptor. If you are a beginning programmer and aren’t sure what functions to use, we suggest that you concentrate on the formatted input functions (see Formatted Input) and formatted output functions (see Formatted Output).
If you are concerned about portability of your programs to systems other than GNU, you should also be aware that file descriptors are not as portable as streams. You can expect any system running ISO C to support streams, but non-GNU systems may not support file descriptors at all, or may only implement a subset of the GNU functions that operate on file descriptors. Most of the file descriptor functions in the GNU C Library are included in the POSIX.1 standard, however.

- 1
- 1

- 4,463
- 28
- 39
System calls are mostly using file descriptor, for example read
and write
. Library function will use the file pointers ( printf
, scanf
). But, library functions are using internally system calls only.

- 12,111
- 21
- 91
- 136

- 5,147
- 14
- 43
- 69
-
I'm not sure why you're saying that library functions are only using internal system calls: If you mean the standard C I/O (or any other for that matter) functions, I'm not sure that's (universally?) true. Otherwise, that's not what you said, so I'd like to see the language in your post cleaned up a little. The last sentence baffles me. – ernie.cordell Feb 28 '14 at 16:14