File handling in C programming

Terry WambuiTerry Wambui
6 min read

In this article, we'll be discussing file handling in c programming, and by the end, you should be able to explain to anyone:

  • How to create, open, close, read and write files

  • What are file descriptors

  • What are the 3 standard file descriptors, what are their purpose and what are their POSIX names

  • How to use the I/O system calls open, close, read and write

  • What are and how to use the flags O_RDONLY, O_WRONLY, O_RDWR

  • What is a system call.

  • What is the difference between a function and a system call

What is file handling?

It refers to the ability of a program to read from or write to files on a computer's hard disk or other storage devices. C provides a set of functions that allow one to open files, read data from them, write data to them, close them, and perform other operations on them.

The basic steps involved in file handling include;

  1. opening a file using the fopen() function.

  2. Reading from or writing to the file using functions like fscanf(), fgets(), fputs(), fwrite() etc.

  3. Closing the file using the fclose() function.

How to create and/ or open a file

You can use the fopen() function to create a file, it takes two arguments and returns a pointer to a file object, which is used to perform file I/O operations.

The syntax is;

FILE *fopen(const char *filename, const char *mode)

the filename is a string that specifies the name of the file to be created, while mode specifies the mode in which the file should be opened.

To create a new file, you need to open it in write mode using the "w" mode specifier.

The mode parameter can take one of the following values;

  1. "r": open the file for reading.

  2. "w": open the file for writing(and create the file if it doesn't exist)

  3. "a": open the file for appending(and create one if it doesn't exist)

  4. "r+": open the file for both reading and writing.

  5. "w+": open the file for both reading and writing(and create the file if it doesn't exist)

  6. "a+": open the file for both reading and appending(and create the file if it doesn't exist)

How to write in a file

If the file exists, the contents will be overwritten. If the file doesn't exist a new file will be created and opened in write mode. Example

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

void main()
{
    FILE *fp = NULL;
    char ch = 'a';

    fp = fopen("filename", "w");
    if (fp == NULL);
    {
        printf("Error\n");
        exit(1);
    }
    fputs(ch, fp);
    fclose(fp);
}

It is important to always close the file. Functions used in writing in a file include; fputc(), fputs() and fprintf().

How to read a file

You can use the fscanf() function or fgets() function to read a file. Example;

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

void main()
{
    FILE *fp = NULL;
    char ch;

    fp = fopen("filename", "r");
    if (fp == NULL);
    {
        printf("Error\n");
        exit(1);
    }
    ch = fgets(fp);
    printf("%c\n", ch);
    fclose(fp);
}

File descriptors

Every time we open a file, the operating system gives us a unique number, which is the file descriptor. It is a small non-negative integer that is used as an index into an array of pointers to file objects maintained by the operating system.

File descriptors can be obtained and accessed using functions like open(), socket(), or accept() and closed using the close() function.

There are 3 standard file descriptors;

  1. Standard input(stdin): used for input operations such as reading data from the keyboard or other input devices. The POSIX name is STDIN_FILENO and its value is always 0.

  2. Standard output(stdout): used for output operations such as printing data on the console or writing to a file. The POSIX name is STDOUT_FILENO and its value is always 1.

  3. Standard error(stderr): used for error messages and other diagnostics output. The POSIX name is STDERR_FILENO and its value is always 2.

System call

These are functions that allow a program to interact with input and output devices such as keyboards, displays, and files.

They provide a way for a program to access and manipulate data from these devices by providing a standardized interface to the OS. I/O system functions include;

  1. open(): used to open a file and create a file descriptor. It takes two arguments; the filename and the access mode. Example; open("filename", 0_RDONLY);

  2. close(): used to close a file descriptor. Takes a single argument; the file descriptor to close. Example result=close(fd);

  3. read(): used to read data from a file descriptor. It takes 3 arguments; the file descriptor to read from, a buffer to store the data, and the number of bytes to read. Example:

    ssize_t byte_read = read(fd, buffer, sizeof(buffer));

  4. write(): used to write data to a file descriptor. It takes 3 arguments; the file descriptor to write to, a buffer containing the data to write and the number of bytes to write. Example;

    ssize_t bytes_written = write(fd, message, sizeof(message));

O_RDONLY | O_WRONLY | O_RDWR : what we need to know

These flags are used to specify the access mode when opening a file using the open() system call.

  1. 0_RDONLY: specifies that the file should be opened for reading only. If you try to write, you'll get an error.

  2. 0_WRONLY: specifies that the file should be opened for writing only. If you try to read from the file using the file descriptor returned by open(), you will get an error.

  3. O_RDWR: specifies that the file should be opened for both reading and writing. You can read and write to the file using the file descriptor returned by open().

In order to use these flags, you need to include the fcntl.h header file, then use open() system call to open a file with the desired access mode.

It is important to note that when opening a file for writing only, or for both reading and writing, if the file doesn't exist, it will be created, if it already exists, its contents will be truncated(overwritten) unless you use the O_APPEND flag in addition to O_WRONLY or O_RDWR.

Difference between a function and a system call

A function is a block of code that performs a specific task and can be called from any part of a program. Functions are defined by users or provided in libraries.

A system call is a request for a service from an operating system kernel. It is a function provided by the OS and it allows user-level processes to interact with the kernel.

A system call provides an interface for processes to perform low-level tasks such as opening a file, creating a process, or allocating memory.

Conclusion

File handling is an essential part of programming that allows us to interact with files and perform various operations on them. The C programming language provides a set of functions and system calls that enable us to open, read, write, and close files. It is important to use the correct mode specifier when opening files to ensure that we can perform the necessary operations on them. Additionally, we must always close files after we finish using them to prevent data loss or corruption. Understanding file handling is crucial for any programmer who needs to work with files in their programs.

I hope this helped! I'll do error handling, file permissions, and ownership on a different post because this one is getting a bit lengthy. But as usual, HAPPY CODING!

Photo credit https://m-ini.me/4rPU

10
Subscribe to my newsletter

Read articles from Terry Wambui directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Terry Wambui
Terry Wambui

I am a software engineering student at Alx Africa.