Random Access File in C++

The functions seekg() and seekp() can be used to move file pointer to any position in a random-access file for input and output.

A file consists of a sequence of bytes. A special marker called file pointer is positioned at one file pointer of these bytes. A read or write operation takes place at the location of the file pointer. When a file is opened, the file pointer is set at the beginning of the file. When you read or write data to the file, the file pointer moves forward to the next data item. For example, if you read a byte using the get() function, C++ reads one byte from the file pointer, and now the file pointer is 1 byte ahead of the previous location, as shown in Figure 13.5.

All the programs you have developed so far read/write data sequentially. This is called sequential access file. That is, the file pointer always moves forward. If a file is open for input, it starts to read data from the beginning to the end. If a file is open for output, it writes data one item after the other from the beginning or from the end (with the append mode ios::app).

The problem with sequential access is that in order to read a byte in a specific location, all the bytes that precede it must be read. This is not efficient. C++ enables the file pointer to jump backward or forward freely using the seekp and seekg member functions on a stream object. This capability is known as random access file.

The seekp (“seek put”) function is for the output stream, and the seekg (“seek get”) func­tion is for the input stream. Each function has two versions with one argument or two argu­ments. With one argument, the argument is the absolute location. For example,

input.seekg(O);

output.seekp(O);

moves the file pointer to the beginning of the file.

With two arguments, the first argument is a long integer that indicates an offset, and the second argument, known as the seek base, specifies where to calculate the offset from. Table 13.4 lists the three possible seek base arguments.

You can also use the tellp and tellg functions to return the position of the file pointer in the file.

Listing 13.18 demonstrates how to access a file randomly. The program first stores 10 student objects into the file and then retrieves the third student from the file.

Listing 13.18 RandomAccessFile.cpp

1 #include <iostream>
2
#include <fstream>
3
#include “Student.h”
4 using namespace std;
5

6 void displayStudent(const Student& student)
7 {
8     cout << student.getFirstName() <<
” “;
9     cout << student.getMi() <<
” “;
10    cout << student.getLastName() <<
” “;
11    cout << student.getScore() << endl;
12 }
13
14
int main()
15 {
16    fstream binaryio;
// Create stream object
17    binaryio.open(“student.dat”, ios::out | ios::binary);
18
19    Student student1(
“FirstName1”, ‘A’, “LastName1”, 10);
20    Student student2(
“FirstName2”, ‘B’, “LastName2”, 20);
21    Student student3(
“FirstName3”, ‘C’, “LastName3”, 30);
22    Student student4(
“FirstName4”, ‘D’, “LastName4”, 40);
23    Student student5(
“FirstName5”, ‘E’, “LastName5”, 50);
24    Student student6(
“FirstName6”, ‘F’, “LastName6”, 60);
25    Student student7(
“FirstName7”, ‘G’, “LastName7”, 70);
26    Student student8(
“FirstName8”, ‘H’, “LastName8”, 80);
27    Student student9(
“FirstName9”, ‘I’, “LastName9”, 90);
28    Student student10(
“FirstName10”, ‘J’, “LastName10”, 100);
29
30    binaryio.write(
reinterpret_cast<char*>
31       (&student1),
sizeof(Student));
32    binaryio.write(
reinterpret_cast<char*>
33       (&student2),
sizeof(Student));
34    binaryio.write(
reinterpret_cast<char*>
35       (&student3),
sizeof(Student));
36    binaryio.write(
reinterpret_cast<char*>
37       (&student4),
sizeof(Student));
38    binaryio.write(
reinterpret_cast<char*>
39       (&student5),
sizeof(Student));
40    binaryio.write(
reinterpret_cast<char*>
41       (&student6),
sizeof(Student));
42    binaryio.write(
reinterpret_cast<char*>
43        (&student7),
sizeof(Student));
44    binaryio.write(
reinterpret_cast<char*>
45       (&student8),
sizeof(Student));
46    binaryio.write(
reinterpret_cast<char*>
47       (&student9),
sizeof(Student));
48    binaryio.write(
reinterpret_cast<char*>
49       (&student10),
sizeof(Student));
50
51    binaryio.close();
52
53   
// Read student back from the file
54    binaryio.open(“student.dat”, ios::in | ios::binary);
55
56    Student studentNew;
57
58    binaryio.seekg(
2 * sizeof(Student));
59
60    cout <<
“Current position is ” << binaryio.tellg() << endl;
61
62    binaryio.read(
reinterpret_cast<char*>
63    (&studentNew),
sizeof(Student));
64
65    displayStudent(studentNew);
66

67    cout << “Current position is ” << binaryio.tellg() << endl;
68
69    binaryio.close();
70
71   
return 0;
72 }

The program creates a stream object in line 16, opens the file student.dat for binary output in line 17, creates ten Student objects in lines 19-28, writes them to the file in lines 30-49, and closes the file in line 51.

The program opens the file student.dat for binary input in line 54, creates a Student object using its no-arg construction in line 56, and moves the file pointer to the address of the third student in the file in line 58. The current position is now at 112. (Note that sizeof(Student) is 56.) After the third object is read, the file pointer is moved to the fourth object. So, the current position becomes 168.

Source: Liang Y. Daniel (2013), Introduction to programming with C++, Pearson; 3rd edition.

Leave a Reply

Your email address will not be published. Required fields are marked *