Random Access Files
Here we will discuss how to access files randomly, forward and backward. Before moving forward or backward within a file, one important factor is the current position inside the file. Therefore, we must understand that there is a concept of file position (or position inside a file) i.e. a pointer into the file. While reading from and writing into a file, we should be very clear from where (which location inside the file) our process of reading or writing will start. To determine this file pointer position inside a file, we have two functions tellg() and tellp().
Position in a File
Let’s say we have opened a file stream myfile for reading (getting), myfile.tellg () gives us the current get position of the file pointer. It returns a whole number of type long, which is the position of the next character to be read from that file. Similarly, tellp () function is used to determine the next position to write a character while writing into a file. It also returns a long number.
For example, given an fstream object aFile:
Streampos original = aFile.tellp();
//save current position
So tellg () and tellp () are the two very useful functions while reading from or writing into the files at some certain positions.
Setting the Position
The next thing to learn is how can we position into a file or in other words how can we move forward and backward within a file. Suppose we want to open a file and start reading from 100th character. For this, we use seekg () and seekp () functions. Here seekg () takes us to a certain position to start reading from while seekp () leads to a position to write into. These functions seekg () and seekp () requires an argument of type long to let them how many bytes to move forward or backward. Whether we want to move from the beginning of a file, current position or the end of the file, this move forward or backward operation, is always relative to some position.. From the end of the file, we can only move in the backward direction. By using positive value, we tell these functions to move in the forward direction .Likewise, we intend to move in the backward direction by providing a negative number. By writing:
aFile. seekg (10L, ios::beg)
We are asking to move 10 bytes forward from the begining of the file. Similarly, by writing:
aFile. seekg (20L, ios::cur)
We are moving 20 bytes in the forward direction starting from the current position. Remember, the current position can be obtained using the tellg () function.By writing:
aFile. seekg (-10L, ios:cur)
The file pointer will move 10 bytes in the backward direction from the current position. With seekg (-100L, ios::end), we are moving in the backward direction by 100 bytes starting from the end of the file. We can only move in the forward direction from the beginning of the file and backward from the end of the file.
seekg() and tellg() Functions
One of the useful things we can do by employing these functions is to determine the length of the file. Think about it, how can we do it. In the previous lessons, we have discussed strlen () function that gives the number of characters inside a string. This function can also be used to determine the length of the string placed inside an array. That will give us the number of characters inside the string instead of the array length. As you already know that the length of the array can be longer than the length of the string inside it. For example, if we declare an array of 100 characters but store "Welcome to the C Tutorial" string in it, the length of the string is definitely smaller than the actual size of the array and some of the space of the array is unused. Similarly in case of files, the space occupied by a file (file size) can be more than the actual data length of the file itself. Why the size of the file can be greater than the actual data contained in that file? The answer is little bit off the topic yet it is be good to discuss. As you know, the disks are electromagnetic devices. They are very slow as compared to the controlling electronic devices like Processors and RAM (Random Access Memory). If we want to perform read or write operations to the disk in character by character fashion, it will be very wasteful of computer time. Take another example. Suppose ,we want to write a file, say 53 bytes long to the disk . After writing it, the next file will start from 54th byte on the disk.
Obviously, this is very wasteful operation of computer time. Moreover, it is also very complex in terms of handling file storage on the disk. To overcome this problem, disks are divided into logical blocks (chunks or clusters) and size of one block is the minimum size to read and write to the disk. While saving a file of 53 bytes, we can’t allocate exactly 53 bytes but have to utilize at least one block of disk space. The remaining space of the block except first 53 bytes, goes waste. Therefore, normally the size of the file (which is in blocks) is greater than the actual data length of the file. When this file will be read from the disk, the whole chunk (block) is read instead of the actual data length. By using seekg () function, we can know the actual data length of the file. For that purpose, we will open the file and go to the end of the file by asking the seekg () function to move 0 bytes from the end of the file as: seekg (0, ios::end). Afterwards, (as we are on end of file position), we will call tellg () to give the current position in long number. This number is the actual data bytes inside the file. We used seekg () and tellg () functions combination to determine the actual data length of a file.
/* This is a sample program
to determine the length of a file. The program accepts the name of the
file as a command-line argument. */
Run this program to see its output that shows different results for both input and output modes.