Having two file descriptors available to access the same file might seem redundant. In a way it is. It’s like having two sets of keys to a car: Yes, one could be a backup, but it’s more common that two different people are using the same car. But first, an example is necessary.
Continuing from last week’s Lesson, the following code opens a file for low-level writing access. Immediately, a second (duplicate) file descriptor is summoned. As with last week’s code, separate write() statements use both descriptors to send text to the file. But this time, after the second descriptor is closed, more text is written to the file by using the remaining, open file descriptor:
2026_08_22-Lesson.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
char filename[] = "test.txt";
int fd1,fd2;
/* open/create the file */
fd1 = creat(filename,0);
/* duplicate the handle */
fd2 = dup(fd1);
if( fd1==-1 || fd2==-1 )
{
fprintf(stderr,"Oh we got file problems!\n");
exit(1);
}
/* write data to the file */
write(fd1,"Hello, ",7);
write(fd2,"world!\n",8);
/* close the duplicate fd */
close(fd2);
/* continue with fd1 */
write(fd1,"I mean Earth!\n",15);
/* clean-up */
close(fd1);
return 0;
}
To reduce the number of lines in the code, I open the file for low-level access then immediately use the dup() function to create the duplicate file descriptor. Both variables (fd1 and fd2) are then tested for success. It would be better to test fd1 immediately after calling the creat() function, which is what I would do with code released to the wild.
Two write() statements use separate descriptors to write text to the file. The text is written sequentially as both descriptors reference the same file, same offset, same everything at this point.
File descriptor fd2 is then closed, but fd1 remains open. So the final write() statement adds text to the file by using fd1.
The program has no output, though the file test.txt is written. Here are its contents:
Hello, world! I mean Earth!
At this point, using the separate file descriptors doesn’t provide any advantage over using a single descriptor. No, the advantage comes by using the fcntl() function on one of the file descriptors. In fact, you might have noticed that the fcntl.h header is included in the source code. This function, which I believe stands for “file control,” lets you manipulate how a file is accessed at a low level, even after the file is opened. It’s this function that makes the second file descriptor useful, through doing so adds a level of complexity that’s a bit too deep for me to get into here. Still, that’s the reason for creating the duplicate.