High-Level and Low-Level Input/Output Functions in C Language

When you access files and devices using the following groups of functions:

  1. High-level or Stream-level I/O
  2. Low –level I/O

The following describes the differences between high-level and low-level I/O functions.

High-level or Stream-level I/O

  • Is more flexible and usually more convenient.

  • Hides complexity from the programmer.

  • When using the I/O functions high-level I/O is slower as compared to the low-level I/O.

Low-level I/O

  • Provides direct access to files and devices.

  • Is complex (Buffer management is to done by the programmer)

  • When using I/O functions, low-level I/O is faster as compared to the high-level I/O.

  • Uses a “file descriptor” to track the status of the file.

File Descriptors

When you perform any read or write operations you need to open a file. You can create a new file to write to it, or you can use an existing file by discarding its previous contents. You need to specific permissions to be able to perform read or write operations.

When you write to a file, the system checks for the existing permissions and if you have permission then the system returns a non-negative integer called a “file descriptor”. In low-level I/O functions a file descriptor is used to identity a file for all subsequent read or write operations.

Low-level I/O functions are used for:

  • Accessing files and devices directly.

  • Reading binary files in large chunks.

  • Performing I/O operations quickly and efficiently.

The low-level I/O system in C provides functions that can be used to access files and devices.

  1. Open()
  2. Close()
  3. Read()
  4. Write()

The open() function

The open() function can be used to open an existing file or to create a new file. This function returns a file descriptor for the file name passed to it. If the file opens sucessfuly then the file position is set to zero position, signifying the beginning of the file.

The open() function has the following syntax:

Int open (char *filename, int flags, int perms);

In the preceeding syntax:

  • The first parameter, *filename is a string that contains the name of file you want to open.

  • The second parameter, flags is an integer that specifies how the file is to be opened as the following table lists.

    Flag Values Description

    Common Values of a flag
                                                          Table 1: Common Values of a flag

  • The third parameter, perms, is the mode of permission with which the file is to be opened. There is a permission associated with files that control read, write and execute access for the owner of the file. This argument is used only when the file is to be created.

    Common Values of a permission
                                                    Table 2: Common Values of a permission
The close() function

The close() function closes the file that was opened using the open() function. It takes the file descriptor as a parameter to close the file. If the file is closed successfully then the value returned is 0. In the case of an error, the close() function returns a value of 1.

The close() function has the following syntax.

Int close (int filedesc);

Example: open() and close() function in C program:
  1. #include<stdio.h>  
  2. #include<conio.h>  
  3. #include<string.h>  
  4. #include<io.h>                                   /*input/outpot header file*/  
  5. #include<stdlib.h>  
  6. main()  
  7. {  
  8.    clrscr();  
  9.    char filename[]="example.txt",O_WRONLY ,O_CREATE;  
  10.    int filedes, close_err;  
  11.    /*open the file , filename for writing or create It if it does not exist*/   
  12.    filedes=open(filename , O_WRONLY | O_CREATE , 0);  
  13.    if(filedes==-1)  
  14.    {  
  15.       printf("The file cannot be opened\n");  
  16.    }  
  17.    else  
  18.    {  
  19.       close_err=close(filedes);  
  20.       if(close_err==-1)  
  21.       {  
  22.          printf("The file cannot be closed\n");  
  23.       }  
  24.    }  
  25.    getch();  
  26.    return 0;  
  27. }  
The read() function

The low-level I/O system defines the read() function for reading data from a file. The read operation starts from the current file position and terminates after all the required bytes have been read.

The read() function has the following syntax:

Int read (int filedes, char *buffer, int size);

In the preceding syntax:
  • The first argument is a file descriptor, that is obtained by opening the file.

  • The second argument is a character array, where the data will be stored during the read operation.

  • The third argument is the number of bytes to be transferred.

The read() function reads the number of bytes that are specified in the parameter size from the file with the descriptor filedes. The results are stored in the buffer. The function returns the number of bytes actually read. A value of zero indicates end of file (except if the value of the size argument is also zero). In the case of an error, the read() function returns -1.

Example

  1. #include<stdio.h>  
  2. #include<conio.h>  
  3. #include<io.h>  
  4. #include<string.h>  
  5. #include<stdlib.h>  
  6. main()  
  7. {  
  8.    char str_read[100];  
  9.    char filename[]="example.txt",O_RDONLY;  
  10.    int filedes;  
  11.    filedes=open (filename,O_RDONLY,0);  
  12.    read(filedes,(char *)str_read,5);  
  13.    str_read[5]='\0';  
  14.    printf("the string is=%s.\n",str_read);  
  15.    close(filedes);  
  16.    getch();  
  17.    return 0;  
  18. }  
read function

The write() function

The write() function enables you to write contents to a file. The arguments passed to the write() function are similar to those of the read() function.

The write() function has the following syntax:

Int write (int filedes, char *buffer, int size);

The write() function picks the number of bytes specified in the parameter size from the buffer and writes it to the file with the descriptor fields. The function returns the number of bytes actually written. This may be the specified number of bytes, but can always be smaller. When the file size is large, the write() function should always be called in an iterating loop, until all the data is written. In the case of an error, the write() function returns -1.

Example
  1. #include<stdio.h>  
  2. #include<conio.h>  
  3. #include<io.h>  
  4. #include<string.h>  
  5. #include<stdlib.h>  
  6. main()  
  7. {
       clrscr();  
  8.    char str_write[]="Krishna Rajput";  
  9.    char filename []="example.txt",O_WRONLY,O_CREATE,O_TRUNC;  
  10.    int filedes,n;  
  11.    // open the file and truncate if it exist.  
  12.    filedes=open(filename,O_WRONLY | O_CREATE | O_TRUNC,0);  
  13.    // write 10 byte of data  
  14.    write(filedes,(char *)str_write,10);  
  15.    getch();  
  16.    return 0;  
  17. }  
Error Handling

Some of the low-level I/O functions produce errors when accessing files. They return error flags, when they fail to perform the specified task. You can find these types of errors using the variable errno.

The following table lists some values of errno that are common to the open() , close() , read()  and write() functions.

Common errno Values
                                                               Common errno Values

Apart from the common values, there are certain errno values that are specific to the open() function. The following table lists the errno values that are specific to the open() function.

errno Values for the open Function
                                                      errno Values for the open() Function

There are certain errno values that are specifies to the write() function. The following table lists the errno values that are specifies to the open() function.

errno Values for thee write Function
                                                   errno Values for thee write() Function

Using Random Access in Files

The read and write on files are usually sequential in nature. Each input and output takes place in a file immediately after the previous one. Random access permits non-sequential file access so that a file can be read or written out of sequence.

The sequence access and random access in files in shown in the following figure.

Using Random Access in Files

In the proceeding figure, a user can move to segment C of the file, by either accessing A, B and C individually or by directly moving to segment C. The method of accessing file contents individually is called sequential access and the method of accessing file contents directly is called random access.

The lseek() Function

The lseek() function returns the file position, as measured in bytes from the beginning of the file. This function is similar to the high-level file routine fseek() except it accepts a file descriptor as an argument instead of a stream. The lseek() function does not require a read or write of the file for positioning it.

The lseek() function has the following syntax:

Long lseek (int filedes, long offset, int origin);

In the preceding syntax: 
  • The first parameter is the file descriptor.

  • The second parameter specifies the number of bytes to move the file position.

  • The third parameter is a constant that specifies whether the offset is relative to the beginning of the file, current file position, or end of the file.

The following table lists the various values of this parameter:

The Offset Values
                                                                     The Offset Values

For example, a user specifies SEEK_END as the value for the origin and sets the file position after the current end of the file and writes the data. In this case, the result will be a file that will contain zeroes up to the specified position after the end of the file. The blocks of zeroes are not actually written to disk, therefore the file takes up less space on disk. The following table lists some instructions for moving to the end or beginning of a file.

Moving within a File
                                                             Moving within a File

Example

  1. #include<stdio.h>
  2. #include<io.h>  
  3. #include<string.h>  
  4. #include<conio.h>  
  5. main()  
  6. {  
  7.    char str_write[]="abcdef";  
  8.    int str_read[10];  
  9.    char filename[]="example.txt",O_RDWR,O_CREATE,O_TRUNC;  
  10.    int filedes;  
  11.    //open the file, Truncate if it exists.  
  12.    filedes=open(filename, O_RDWR | O_CREATE | O_TRUNC);  
  13.    //write 5 bytes of data  
  14.    write (filedes, (char *)str_write,5);  
  15.    //seek the beginning of the file  
  16.    lseek(filedes,(long) str_read,5);  
  17.    //Terminate the data we have read with a null character  
  18.    str_read[5]='\o';  
  19.    printf("The string is =%s.\n",str_read);  
  20.    close(filedes);  
  21.    getch();  
  22.    return 0;  
  23. }  


Similar Articles