When you access files and devices using the following groups of functions:
- High-level or Stream-level I/O
- 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.
- Open()
- Close()
- Read()
- 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
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.
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:
- #include<stdio.h>
- #include<conio.h>
- #include<string.h>
- #include<io.h> /*input/outpot header file*/
- #include<stdlib.h>
- main()
- {
- clrscr();
- char filename[]="example.txt",O_WRONLY ,O_CREATE;
- int filedes, close_err;
-
- filedes=open(filename , O_WRONLY | O_CREATE , 0);
- if(filedes==-1)
- {
- printf("The file cannot be opened\n");
- }
- else
- {
- close_err=close(filedes);
- if(close_err==-1)
- {
- printf("The file cannot be closed\n");
- }
- }
- getch();
- return 0;
- }
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
- #include<stdio.h>
- #include<conio.h>
- #include<io.h>
- #include<string.h>
- #include<stdlib.h>
- main()
- {
- char str_read[100];
- char filename[]="example.txt",O_RDONLY;
- int filedes;
- filedes=open (filename,O_RDONLY,0);
- read(filedes,(char *)str_read,5);
- str_read[5]='\0';
- printf("the string is=%s.\n",str_read);
- close(filedes);
- getch();
- return 0;
- }
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
- #include<stdio.h>
- #include<conio.h>
- #include<io.h>
- #include<string.h>
- #include<stdlib.h>
- main()
- {
clrscr();
- char str_write[]="Krishna Rajput";
- char filename []="example.txt",O_WRONLY,O_CREATE,O_TRUNC;
- int filedes,n;
-
- filedes=open(filename,O_WRONLY | O_CREATE | O_TRUNC,0);
-
- write(filedes,(char *)str_write,10);
- getch();
- return 0;
- }
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 ValuesApart 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() FunctionThere 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() FunctionUsing 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.
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
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
Example
- #include<stdio.h>
- #include<io.h>
- #include<string.h>
- #include<conio.h>
- main()
- {
- char str_write[]="abcdef";
- int str_read[10];
- char filename[]="example.txt",O_RDWR,O_CREATE,O_TRUNC;
- int filedes;
-
- filedes=open(filename, O_RDWR | O_CREATE | O_TRUNC);
-
- write (filedes, (char *)str_write,5);
-
- lseek(filedes,(long) str_read,5);
-
- str_read[5]='\o';
- printf("The string is =%s.\n",str_read);
- close(filedes);
- getch();
- return 0;
- }