Lower Level File Handling in Linux

In this section we will describes functions for performing low-level input/output operations on file descriptors.

In lower level file handling we will study the basic opening, closing, reading, and writing a file through a file descriptor which acts as a pointer or cursor to a file.It is called lower level file handling because it will execute or do operations on kernel level not even can open a binary file only to read or write but can open a device also. This is the basically main difference between  open and fopen call.

Difference between Lower Level File Handling and Upper Level File Handling:

In lower level file handling the call is directly made to the kernel of the OS. i.e. for example, there is a open, read, write system call to open a file or a device, so in this that call is directly made to the kernel level and hence faster and more efficient but in Upper Level File Handling there is call in the user space of the OS and actually the upper level system calls uses lower level system calls to write and read. For example, there is a fopen, fwrite and fread system calls that will call open, write and read system calls to perform actions.

But in these system calls operations are limited to user space. i.e. in fopen system call we could not open a device, here we cal open a binary file or a normal text file to write and read in it similarly with file descriptor.

Uses of lower level file handling system calls –

  • For reading binary or text files .
  • To open a device with a descriptor to transfer data to a external device through serially.
  • To pass descriptors to a child process. (The child can create its own stream to use a descriptor that it inherits, but cannot inherit a stream directly.)

    1. open system call

The open() call is used to open a file to perform read and write operations on it and it returns a file descriptor, a small, non-negative integer for use in subsequent system calls i.e. read and write.

The file descriptor returned by a successful call will be the lowest-numbered file descriptor not currently open for the process.

Syntax :

 path name – contains the location or name of file on which the read and write operations are to be performed.

Flags –

O_RDONLY               open for reading only

O_WRONLY              open for writing only

O_RDWR                  open for reading and writing

O_NONBLOCK        do not block on open

O_APPEND              append on each write

O_CREAT                create file if it does not exist

O_TRUNC              truncate size to 0

O_EXCL                 error if create and file exists

O_SHLOCK          atomically obtain a shared lock

O_EXLOCK          atomically obtain an exclusive lock

Return Value : It will return a file descriptor value through which we can write or read into that file. This will be illustrated by an example later.

IMPORTANT POINT TO NOTE :The file descriptor numbers 0,1,2 are reserved i.e. 0 for take input 1 for display and 2 for errors.It means that if we want to display anything on a terminal  then we can simply use,write(1,”HELLO”,5);It will display HELLO on terminal. i.e. it behaves like an printf function. Here 1 is the value of file descriptor.And we want to use take an input from a user without using a  scanf function the simply use read (0,buff,sizeof(buff));It will take input from user and stire that result in a buff variable.

            2.write system call :

Syntax :-

#include <unistd.h>

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

Data Type:  ssize_t

This data type is used to represent the sizes of blocks that can be read or written in a single operation. It is similar to size_t, but must be a signed type.

Here 1st argument is the file descriptor that is  come from the open call after opening a file or a device and 2nd argument is the buffer name and 3rd argument is the size of that buffer or size that we want to write into a file.

On success, the number of bytes written are returned (zero indicates nothing was written). On error, -1 is returned, and errno is set appropriately.

        3.read system call :

Syntax :

#include <unistd.h>

ssize_t read (int filedes, void *buffer, size_t size)

Data Type:  ssize_t

This data type is used to represent the sizes of blocks that can be read or written in a single operation. It is similar to size_t, but must be a signed type.

Here 1st argument is the file descriptor that is  come from the open call after opening a file or a device and 2nd argument is the buffer name and 3rd argument is the size of that buffer or size that we want to write into a file.

The read function reads up to size bytes from the file with descriptor filedes, storing the results in the buffer. (This is not necessarily a character string, and no terminating null character is added.)

The return value is the number of bytes actually read. This might be less than size; for example, if there aren’t that many bytes left in the file or if there aren’t that many bytes immediately available. The exact behavior depends on what kind of file it is. On error, -1 is returned.

      4. Close system call :

Syntax :

             int close (int filedescriptor)

The function close closes the file descriptor filedescriptor. Closing a file has the following consequences:

  • The file descriptor is deallocated.
  • Any record locks owned by the process on the file are unlocked.

When all file descriptors associated with a pipe or FIFO have been closed, any unread data is discarded.

Setting the File Position of a Descriptor

To read the current file position value from a descriptor, use lseek.

Syntax : off_t lseek (int filedes, off_t offset, int whence)

The lseek function is used to change the file position of the file with descriptor filedes.

The whence argument specifies how the offset should be interpreted, in the same way as for the fseek function, and it must be one of the symbolic constants SEEK_SET, SEEK_CUR, or SEEK_END.

SEEK_SET

Specifies that whence is a count of characters from the beginning of the file.

SEEK_CUR

Specifies that whence is a count of characters from the current file position. This count may be positive or negative.

SEEK_END

Specifies that whence is a count of characters from the end of the file. A negative count specifies a position within the current extent of the file; a positive count specifies a position past the current end. If you set the position past the current end, and actually write data, you will extend the file with zeros up to that position.

The return value from lseek is normally the resulting file position, measured in bytes from the beginning of the file. You can use this feature together with SEEK_CUR to read the current file position.

EXAMPLES  : –

1.open a file with ‘open’ system call

 

2.open a device with ‘open’ system call