C programming file descriptors

HacksLand | The computer science playground

Posted by Thilan Dissanayaka on May 03, 2020

File access is an essential feature of any programming language. In C we can use two methods to access file system. Those are file descriptors and file streams. In this document we are going to see how we can use file descriptors to access files.


With file descriptors we have some functions like open, close, read, write etc. to access files. A file descriptor is actually a integer number. Every opened file has it's own unique number. We call it a file descriptor. When we open a file with open() function it return a file descriptor. Then we can use this file descriptor to perform further operations on that file. For an example , if we want to read data from that opened file we use given file descriptor as an argument for the read function.

Let's talk more about the open function. First argument to this function is name of the file  we want to open. Then we supply some other arguments to specify the mode of opening. I mentioned it will return a file descriptor when opening a file But this is not happening every time. If it fails to open the file return value will be -1. So before we do further operations on opened file we must check the return value of the open() function. If it equal to -1 we know open() function couldn't open the file.

In the following code we can see the usage of open() function.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>


int main(int argc, char const *argv[])
{
 int fd;
 char buff[1000];
 
 if ((fd = open("file.txt",  O_RDONLY)) == -1)
 {
  printf("file opening failed\n");
  exit(0);
 }else{
  printf("file opening successful\n");
  printf("file descriptor: %d\n", fd);
 }
}

(The string.h header file and declared character array is not required at now. those are for next steps.)

At the top of main function we have declared an integer variable called fd. this is to hold the file descriptor value. Then we have used an if statement to check the return value of open function. If it is -1, we display an error and exit the program. If not we can continue the program. First argument to open function is "file.txt" . This is the physical name of the file. Next we have specified O_RDONLY. This indicate we want to open file in read only mode. Hear are some other arguments we can use.

O_RDONLY This instructs the open function to Open file in read-only mode. If we open a file in read only mode and try to write something, write function will fail to do it and return -1.

O_WRONLY This will open file for write-only access.
O_RDWR This option can be used to open file for both read and write access.

 

O_CREAT This mode can be used to create the file if it doesn’t exist.

O_APPEND If we use this option all data we write to the file will append to the end of the file. If there are already some data in the file they will kept as that.

O_TRUNC If the file already exists with the specified name it will be truncated.

 


Next we use read function to read content of a file. Following is the definition of the function.

ssize_t read(int fd, void *buf, size_t count);


It's first argument is a file descriptor. We have to give previously opened file's descriptor as the argument. Second argument is a pointer. Read function read the content from the given file and save it on this pointed location. We can give the address of previously allocated buffer space as this pointer. Third argument is the number of bytes to read from file. This file return the number of bytes it read from the file if it successfully read the file. If it fails it will return -1.

Following code shows the usage of read function.

if (read(fd, buff, sizeof(buff)) == -1)
{
 printf("Error while reading file\n");
 exit(0);
}else{
 printf("File contents: %s\n", buff);
}

You know the name of character buffer space "buff" is a pointer to that buffer space. Also we used sizeof() function to get buffer size. We read data from the file and save it  in the buffer space.

Let's see complete code to read a file.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char const *argv[])
{
 int fd;
 char buff[1000];
 
 if ((fd = open("file.txt",  O_RDONLY)) == -1)
 {
  printf("file opening failed\n");
  exit(0);
 }else{
  printf("file opening successful\n");
  printf("file descriptor: %d\n", fd);





  if (read(fd, buff, sizeof(buff)) == -1)
  {
   printf("Error while reading file\n");
   exit(0);
  }else{
   printf("File contents: %s\n", buff);
  }

 }

 return 0;
}

 

I compile and run it on a Linux mashing. Also before run it I created a file named "file.txt" with some sample text using echo command.

[email protected]:/c# nano fd.c
[email protected]:/c# echo "Hi, this is a sample text in the file" > file.txt
[email protected]:/c# cat file.txt
Hi, this is a sample text in the file

[email protected]:/c# gcc fd.c -o fd
[email protected]:/c# ./fd
file opening successful
file descriptor: 3
File contents: Hi, this is a sample text in the file

 

 

Awesome. It worked as expected.

Next I write something to the file.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char const *argv[])
{
 int fd;
 char buff[] = "Hi, I'm going to written into the file\n";

 if ((fd = open("file.txt",  O_WRONLY)) == -1)
 {
  printf("file opening failed\n");
  exit(0);
 }else{
  printf("file opening successful\n");
  printf("file descriptor: %d\n", fd);





  if (write(fd, buff, strlen(buff)) == -1)
  {
   printf("Error while writing to file\n");
   exit(0);
  }else{
   printf("wrote %d bytes to the file:\n", strlen(buff));
  }

 }


 return 0;
}

 

write() function takes three arguments. First is file descriptor. Second is a pointer to a location. Function reads data from this location and write it to the file. Third argument specify how many bytes we should write at the file.

Let's compile and ruin it to see if it work.

[email protected]:/c# nano fd.c
[email protected]:/c# gcc fd.c -o fd

[email protected]:/c# touch file.txt
[email protected]:/c# cat file.txt

[email protected]:/c# ./fd
file opening successful
file descriptor: 3
wrote 39 bytes to the file:

[email protected]:/c# cat file.txt
Hi, I'm going to written into the file

 


It is a good programming practice to close the file descriptor after we done the operation on opened file.
We can use close() function to do this It only take the file descriptor as the argument.

So in this document we saw how we can use file descriptors to access files. In next article we are going to see how we can use file streams.

Hi, I'm Thilan. An engineering student from SriLanka. I love to code with Python, JavaScript PHP and C.

Also read

Sep 08
Build A Simple Web shell

A web shell is a piece of code that written to get control over a web server. It is helpful for....

Aug 12
Linux directory structure

Using a Linux distro is a completely different thing. If you are a windows user you can see they....

Oct 17
Command line arguments in C

Hi guys, In this document we are going to see how we can use command line argumentsin C programs .....

Comments