Random-Access File in C++:


In this tutorial, we introduce the concept of random file access. Unlike sequential files,random access files allow us to read or write data in any order. Think of a random access file like a CD or a record where you can play any song directly without having to go through the others. If you want to play the first song, then the sixth, and then the fourth, you can do so without regard to the original recording order. While random file access might require more programming effort, it offers greater flexibility in how we access file data.

Random file access lets us read or write any part of a file without processing the entire file. This capability allows for quick data searches, modifications, deletions, and more. While random access files can be opened and closed similarly to sequential files, they require additional functions to navigate the file randomly. This extra effort is rewarded with increased flexibility, power, and speed in file handling.

Consider the data files of a large credit card organization. When a purchase is made, the store contacts the credit card company for authorization. The company's files contain millions of names, making it impractical to read records sequentially to find a specific one quickly. Instead, random file access allows the system to go directly to the required record, just as you would select a song on a CD.

Random file access enables programs to treat files like large arrays, allowing data manipulation in any order. Here are some key operations you can perform with random access files:

To perform these operations, we need to understand the concept of file pointers. A file pointer keeps track of the current read/write position within the file. By default, when a file is opened, the file pointer is at the beginning, but it can be moved to any position using specific functions.

C++ provides four functions for this purpose:

seekg()

Moves the input pointer to a specified location for reading.


seekp()

Moves the output pointer to a specified location for writing.


tellg()

Returns the current position of the input pointer.


tellp()

Returns the current position of the output pointer.


The seekg()function moves the input pointer to a specified location within the file for reading. Its syntax is:

fileObject.seekg(long_num, origin);

In Above Syntax:.

  • fileObject: The pointer to the file.
  • long_num: The number of bytes to skip.
  • origin: The starting point for the skip (e.g., beginning, current position, or end).

Possible values for "origin":

Regardless of how far into a file you have read, using this syntax will move the file pointer back to the beginning of the file.

The basic syntax to use this origin with the seekg()function is:

seekg(long_num, ios::beg)

Here's a simple example to illustrate how to use this origin value with the seekg()function in a C++ program. This example skips the first 7 bytes from the beginning of the file:

IOS::BEG - C++ EXAMPLE Copy to Clipboard  
#include <fstream>
#include <iostream>
using namespace std;

int main() {
    ofstream myFile;
    ifstream file;
    char ch[30];
    char text;

    cout << "Enter some text here: " << endl;
    cin.getline(ch, 30);

    myFile.open("InfoBrother.txt", ios::out);
    if (myFile) {
        myFile << ch;
        cout << "Data stored successfully.\n";
    } else {
        cout << "Error while opening file.\n";
    }
    myFile.close();

    file.open("InfoBrother.txt", ios::in);
    if (file) {
        file.seekg(7, ios::beg);
        cout << "Output (after skipping the first 7 bytes): ";

        while (!file.eof()) {
            file.get(text);
            cout << text;
        }
    } else {
        cout << "Error while opening file.\n";
    }
    file.close();

    return 0;
}

Stay at the current position. Using this syntax, the file pointer will remain at its current location.

The basic syntax to use this origin with the seekg()function is:

seekg(long_num, ios::cur)

Here's a simple example to illustrate how to use this origin value with the seekg()function in a C++ program. This example skips the first 7 bytes from the beginning and then moves back 2 bytes:

IOS::CUR - C++ EXAMPLE Copy to Clipboard  
#include <fstream>
#include <iostream>
using namespace std;

int main() {
    ofstream myFile;
    ifstream file;
    char ch[30];
    char text;

    cout << "Enter some text here: " << endl;
    cin.getline(ch, 30);

    myFile.open("InfoBrother.txt", ios::out);
    if (myFile) {
        myFile << ch;
        cout << "Data stored successfully.\n";
    } else {
        cout << "Error while opening file.\n";
    }
    myFile.close();

    file.open("InfoBrother.txt", ios::in);
    if (file) {
        file.seekg(7, ios::beg);
        file.seekg(-2, ios::cur);
        cout << "Output (after skipping 7 bytes and moving back 2): ";

        while (!file.eof()) {
            file.get(text);
            cout << text;
        }
    } else {
        cout << "Error while opening file.\n";
    }
    file.close();

    return 0;
}

Go to the end of the file. Using this syntax, the file pointer will move to the end of the file, regardless of its current position.

The basic syntax to use this origin with the seekg()function is:

seekg(long_num, ios::end)

Here's a simple example to illustrate how to use this origin value with the seekg()function in a C++ program. This example moves the pointer 11 bytes back from the end of the file:

IOS::END - C++ EXAMPLE Copy to Clipboard  
#include <fstream>
#include <iostream>
using namespace std;

int main() {
    ofstream myFile;
    ifstream file;
    char ch[30];
    char text;

    cout << "Enter some text here: " << endl;
    cin.getline(ch, 30);

    myFile.open("InfoBrother.txt", ios::out);
    if (myFile) {
        myFile << ch;
        cout << "Data stored successfully.\n";
    } else {
        cout << "Error while opening file.\n";
    }
    myFile.close();

    file.open("InfoBrother.txt", ios::in);
    if (file) {
        file.seekg(-11, ios::end);
        cout << "\nThe last 11 bytes are: ";

        while (!file.eof()) {
            file.get(text);
            cout << text;
        }
    } else {
        cout << "Error while opening file.\n";
    }
    file.close();

    return 0;
}

In each example, we included error checks to avoid issues, which is essential for robust programming. C++ provides several functions to handle errors:

bad()

Returns true if an error occurs during a read or write operation.


fail()

Returns true in cases similar to bad() and if a format error occurs.


eof()

Returns true if the end of a file opened for reading is reached.


good()

Returns false if any of the previous functions would return true.


The write()function is employed with an Output-Pointer object to write a block of data. It utilizes the binary data version rather than text. With write(), each value is stored in binary format, creating records with fixed lengths. This function requires three arguments:

  • A Pointer to Character
  • The Address of the object
  • The Object's size

The basic syntax to use this function is:

fileObject.write((char*)&Obj, sizeof(Obj));

Below is an example demonstrating the write()function and its application in writing data blocks within our C++ program. Scroll down to view the complete example.

//Example: Writing Employee Data
void WriteEmployee() {
    ofstream fp("Employee.txt", ios::out);
    if (fp) {
        Emp.getEmp_data();
        fp.write((char*)&Emp, sizeof(Emp));
        cout << "Record stored successfully.\n";
    }
    fp.close();
}

The read()function is employed with an Input-Pointer object to read a block of data. It functions similarly to the write()function but is used for reading data.

The basic syntax to use this function is:

fileObject.read((char*)&Obj, sizeof(Obj));

Below is an example illustrating the concept of the read()function and its utilization in reading data blocks within our C++ program. Scroll down to view the complete example.

//Example: Reading Employee Data
void W_displayEmp() {
    ifstream fp("Employee.txt", ios::in);
    if (fp) {
        while (fp.read((char*)&Emp, sizeof(Emp))) {
            Emp.showemp_data();
        }
        fp.close();
    }
}

Below is a comprehensive example demonstrating the write()and read()functions for writing and reading data, respectively. Run the code yourself to grasp the functionality of these functions and discover how they can enhance efficiency in C++ programming.

READ | WRITE - EXAMPLE C++ Copy to Clipboard  
/* Write() and Read() function Example: InfoBrother */

#include <fstream> // Required for file operations
#include <iostream> // Required for input/output
using namespace std;

// Class to handle employee data
class Employee {
private:
    char name[30];
    char employee_ID[20];
    char joining_DATE[20];
    char position[20];
    char marital_status[10];
    char age[10];
    char salary[20];
    char comment[80];

public:
    // Method to input employee data
    void getEmp_data() {
        cout << "Welcome To InfoBrother: " << endl;
        cout << "======================" << endl;
        cout << "\n\n Employee Name: ";
        cin.getline(name, 30);
        cout << " Employee ID: ";
        cin.getline(employee_ID, 20);
        cout << " Joining Date: (DD/MM/YYYY) ";
        cin.getline(joining_DATE, 20);
        cout << " Job Description: ";
        cin.getline(position, 20);
        cout << " Single / Married: ";
        cin.getline(marital_status, 10);
        cout << " Employee Age: ";
        cin.getline(age, 10);
        cout << " Salary Per Month: $ ";
        cin.getline(salary, 20);
        cout << " Comment: ";
        cin.getline(comment, 80);
    }

    // Method to display employee data
    void showemp_data() {
        cout << "\n\nEMPLOYEE DATA: " << endl;
        cout << "=================================" << endl;
        cout << "\n Name: " << name << endl;
        cout << " Employee ID: " << employee_ID << endl;
        cout << " Position: " << position << endl;
        cout << " Date of joining: " << joining_DATE << endl;
        cout << " Age of Employee: " << age << endl;
        cout << " Total Salary: $ " << salary << endl;
        cout << " Marital Status: " << marital_status << endl;
        cout << " Comment: " << comment << endl;
    }
};

// Class to manage file operations
class Library {
public:
    Employee Emp; // Employee class object
    fstream fp; // File object

    // Method to write employee data into the file
    void WriteEmployee() {
        fp.open("Employee.txt", ios::out); // Open file for writing
        if (fp) { // Error checker
            Emp.getEmp_data(); // Function call
            fp.write((char*)&Emp, sizeof(Emp)); // Write into file
            cout << "Record Stored Successfully." << endl;
        }
        fp.close(); // Close file
    }

    // Method to display data from file
    void DisplayEmp() {
        fp.open("Employee.txt", ios::in); // Open file for reading
        if (fp) { // Error checker
            while (fp.read((char*)&Emp, sizeof(Emp))) { // Read data from file
                Emp.showemp_data(); // Function call
            }
            fp.close(); // Close file
        }
    }
};

int main() {
    Library lib; // Library class object
    lib.WriteEmployee(); // Write function call
    lib.DisplayEmp(); // Display function call

    return 0;
}

The remove()function is utilized to delete any file from a record. It takes a single argument, which is the filename to be deleted.

The basic syntax to use this function is:

remove(fileName);

The rename()function is employed to rename any file. It requires two arguments: the old name of the file and the new name for the file.

The basic syntax to use this function is:

rename(oldName, newName);

Below is a complete example demonstrating how the remove()and rename()functions operate. Copy and paste this code into your compiler, then run the program. Enter your text and terminate the program. Navigate to your folder and locate the "InfoBrother.txt" file. Open the file to observe its contents.

RENAME | REMOVE - C++ EXAMPLE Copy to Clipboard  
#include <fstream>
#include <iostream>
using namespace std;

int main() {
    fstream fp, fp1;
    char text[50];
    char ch;

    cout << "Enter some text here: " << endl;
    cin.getline(text, 50);

    fp.open("InfoBrother.txt", ios::out);
    if (fp) {
        fp << text;
        cout << "File created successfully.\n";
    } else {
        cout << "Error while opening file.\n";
    }
    fp.close();

    fp.open("InfoBrother.txt", ios::in);
    if (!fp) {
        cout << "Error while opening file.\n";
        return 0;
    }
    fp1.open("InfoBrother_temp.txt", ios::out);
    if (!fp1) {
        cout << "Error while opening file.\n";
        return 0;
    }

    fp.seekg(0, ios::end);
    int size = fp.tellg();
    fp.seekg(0, ios::beg);
    int pos = 0;

    while (fp) {
        if (pos >= size / 2 && pos < size / 2 + 5) {
            ch = '*';
            fp1.put(ch);
        } else {
            ch = fp.get();
            fp1.put(ch);
        }
        pos++;
    }

    fp.close();
    fp1.close();

    remove("InfoBrother.txt");
    rename("InfoBrother_temp.txt", "InfoBrother.txt");

    cout << "File content is edited successfully.\n";

    return 0;
}

Random file access in C++ offers powerful capabilities for reading and writing data efficiently. By using functions like seekg(), seekp(), tellg(), tellp(), write(), and read(), we can manipulate file data in any order. This flexibility is essential for many applications, such as database management and large-scale data processing. Understanding and using these functions will help you build more robust and efficient file-handling programs.