Using a CSV file from C++ program | Flight booking system

Using a CSV file to store data from a C++ program





I used objects to store each flight's data in a previous project. This made the program hold the data in the random access memory. This can pose a problem as it is not a permanent way of storing the data and will be erased once the program ends. To counter this, I initially thought of using a database with C++. I sought help with this online and was told about using a CSV file before using a database.

A CSV file is a file format that stands for Comma Separated Values. This file can be used to represent rows in the form of lines and column data as values in each line that lie in the same position in their respective line. This way CSV files can be used to represent tabular data.

Having said all that, we should look at how we can create a CSV file.

Creating a CSV file

There are two ways of creating a CSV file. You can either use a text editor such as Notepad in Windows, or you can use a sheets application such as MS Excel in Windows.

I have used MS Excel to create my CSV files. Here are the steps to do it this way.

Go to MS Excel and create a new blank sheet. Decide the format of your CSV file. Once you have a final version ready, click on the "Save As" button. You must rename the file with the extension .csv at the end and change the file format to CSV.


A CSV file in Excel like the one shown below

Looks like this in text form:



The C++ program

The system defines an object for each flight. The flight has an ID given to it upon its creation by the constructor. This ID helps in locating the particular flight's data in the CSV file. Two CSV files are used by the system. One for storing the general details about a flight (flight's name, from, to, time, schedule, etc) and the other for storing more specific information, i.e., the names of the passengers who have booked a ticket for the flight and their corresponding days of departure. These files need to be created.

The format for them is:

and


The above image in text form:


The flight object

Now let me take you through each of the internal functions of the flight class.

The preference checker:

int check_pref(char *from_d, char *to_d, char *day){              //internal function to check if the user preferences match with the flight properties
        vector<string> flight_props;
        string flight_line;
        flight_props.clear();

        ifstream properties("flight_objects_prop.csv");
        if(properties.is_open()){
            int current_line = 0;
            while(getline(properties, flight_line)){         //navigate to the line of the flight object
                current_line++;
                if(current_line - 1 == id){
                    break;
                }
            }
            stringstream ss(flight_line);                    //used to help split the line string into words
            string prop_word;
            while(getline(ss, prop_word, ',')){              //to store each column data of the row
                flight_props.push_back(prop_word);
            }

            if((flight_props[1] == from_d) && (flight_props[2] == to_d)){       //checking if the user preferences match with the flight properties
                for(int i = 4; i <= 10; i++){
                    if(flight_props[i] == day){
                        cout << "\nFlight " << flight_props[0] << " has been identified. Press " << id << " to select it.\n";
                        properties.close();
                        return 1;
                    }
                }
            }
            return 0;
        }
        else {
            cout << "Could not open CSV file.";
            return -1;
        }
    }

The three things a person might have in their mind if they were to book a flight ticket would be: where from, where to, and on what day. These preferences are asked from the user and then matched against each flight to check if any flight fits the user's choices. The check_pref(char *from, char *to, char *day) function performs this task. 

A string vector is created to store the column data of the flight object. This data is read from the CSV file. The file is opened using the ifstream class. Each line in the file represents a particular flight. Hence, we must navigate to the correct line first before proceeding to store it in the string vector.

To go through the lines one by one while also keeping track of the line number a while loop is used with the getline() function and a tracking integer variable is declared which is incremented with each step of the while loop. If the tracking variable satisfies a formula with the id of the flight, we have reached the right line. At this point, it breaks out of the while loop, having stored the line in the string "flight_line".

Now, we must extract each column data from this line. To do this, we use the getline() function after converting the string "flight_line" into a stream using the stringstream method and declaring another string "prop_word" to temporarily store each column data to push into the string vector "flight_props".

Now the conditions of user preferences matching with the flight properties can be checked. 

The ticket booker:

Once the preferences have been matched and the user has selected a particular flight, the selected flight must accommodate the user's name and the day of their departure into its records. For the records, a separate CSV file was created("passengers.csv"). 


    void book_ticket(char *name, char *day){
        ifstream passengers_read("passengers.csv");             //file opened for reading
        string pass_names;
        vector<string> passengers;
        if(passengers_read.is_open()){
            while(getline(passengers_read, pass_names)){
                passengers.push_back(pass_names);                   //storing each line from csv file in a string vector
            }

            passengers_read.close();
        }
        else {
            cout << "\nCould not access passenger list.";
        }

        ofstream passengers_write("passengers.csv");             //file opened for writing

        if(passengers_write.is_open()){
            int name_line_number = id + (id - 1);
            int day_line_number = id + (id - 1) + 1;
            for(int i = 0; i < passengers.size(); i++){
                if(i == name_line_number - 1){
                    stringstream ss(passengers[i]);
                    string temp;
                    vector<string> temp_vector;
                    while(getline(ss, temp, ',')){
                        temp_vector.push_back(temp);
                    }
                    for(int i = 0; i < temp_vector.size(); i++){
                        if(temp_vector[i] == "0"){
                            temp_vector[i] = name;                      //replace zero with the passenger name
                            break;
                        }
                    }
                    string temp2;
                    for(int i = 0; i < temp_vector.size(); i++){
                        temp2 = temp2 + temp_vector[i] + ",";                 //combine all strings from the temp vector into a single string temp2
                    }

                    passengers_write << temp2 << "\n";                  //write the combined string temp2 to the csv file
                }
                else if(i == day_line_number - 1){
                    stringstream ss(passengers[i]);
                    string temp3;
                    vector<string> temp_vector3;
                    while(getline(ss, temp3, ',')){
                        temp_vector3.push_back(temp3);
                    }
                    for(int i = 0; i < temp_vector3.size(); i++){
                        if(temp_vector3[i] == "0"){
                            temp_vector3[i] = day;                      //replace zero with the day given by the passenger
                            break;
                        }
                    }
                    string temp4;
                    for(int i = 0; i < temp_vector3.size(); i++){
                        temp4 = temp4 + temp_vector3[i] + ",";                //combine all strings into one
                    }

                    passengers_write << temp4 << "\n";
                }
                else {
                    passengers_write << passengers[i] << "\n";            //skipping all other lines
                }                                                         //these lines are written back to the file as they were
            }
            passengers_write.close();
        }
        else{
            cout << "\nCould not access passenger list.";
        }
    }

The file is first opened for reading with the ifstream class. In this part of the function, the lines are read from the file and stored in a string vector. After all lines have been stored, the file is closed.

The file is then reopened with the ofstream class for overwriting the previous text with a modified text. A for loop iterates over the string vector storing the lines and when the required lines are encountered, it is broken down to its column data. This column data is manipulated with the user data such as name and day of departure. After the column data have been manipulated appropriately, all the column data (vector elements) are combined into one string and written into the CSV file that was opened for writing. The other lines are written as they were before(without manipulation).

The file is then closed.

The ticket generator:

Once the user data has been accommodated into the flight's internal records, a ticket must be printed on the screen for the user. 


void generate_ticket(char *name, char *day){
        ifstream ticket("flight_objects_prop.csv");
        vector<string> details_lines;
        string line_string;
        if(ticket.is_open()){
            while(getline(ticket, line_string)){
                details_lines.push_back(line_string);                //obtaining the lines from csv file
            }
        }
        else{
            cout << "\nCould not open file.";
        }

        vector<string> details_main;
        string main_string;

        int current_line = 0;
        for(int i = 0; i < details_lines.size(); i++){
            current_line++;
            if(current_line - 1 == id){
                stringstream ss(details_lines[i]);
                while(getline(ss, main_string, ',')){
                    details_main.push_back(main_string);             //obtaining the line containing the required data
                }
            }
        }

        char *day_full;
        if(day == "mo"){
            day_full = "Monday";
        }
        else if(day == "tu"){
            day_full = "Tuesday";
        }
        else if(day == "we"){
            day_full = "Wednesday";               //obtaining the text to be displayed from user selected day
        }
        else if(day == "th"){
            day_full = "Thursday";
        }
        else if(day == "fr"){
            day_full = "Friday";
        }
        else if(day == "sa"){
            day_full = "Saturday";
        }
        else if(day == "su"){
            day_full = "Sunday";
        }

           //printing ticket after retrieving data from the CSV file
        cout << "---------------------------\n\n";
        cout << "Name: " << name;
        cout << "\nFrom: " << details_main[1] << "\tTo: " << details_main[2];
        cout << "\nFlight name: " << details_main[0];
        cout << "\nDay: " << day_full;
        cout << "\nTime: " << details_main[3];
        cout << "\n\n\tThank you for choosing to fly with us!";
    }

The file is again opened with the ifstream class for reading. Each line is stored in a string vector. The required line is identified and its data is then parsed to extract individual column data for the required flight object.

The flight ticket is then printed onto the screen using this extracted data and data from function parameters.

The driver program:


int main(){
    char name[15], *from, *to, *day;
    int from_num, to_num, day_num;

    flight A1(1), A2(2), A3(3), A4(4);                                      //flight objects declared

    cout << "\tWelcome to Random Airlines\n";
    cout << "---------------------------\n";

    cout << "Please enter your name: ";
    cin >> name;

    label1:
    cout << "\nPlease select departure city:\n";
    cout << "1 for Mumbai\n2 for New York\n3 for Dubai\n4 for Berlin\n";
    cin >> from_num;
    switch(from_num)
    {
    case 1:
        from = "Mumbai"; break;
    case 2:
        from = "New York"; break;
    case 3:
        from = "Dubai"; break;
    case 4:
        from = "Berlin"; break;
    default:
        cout << "Invalid input";
        goto label1;
    }

    label2:
    cout << "Please select city for arrival:\n";
    cout << "1 for Dubai\n2 for London\n3 for Mumbai\n4 for New York\n";
    cin >> to_num;
    switch(to_num)
    {
    case 1:
        to = "Dubai"; break;
    case 2:
        to = "London"; break;
    case 3:
        to = "Mumbai"; break;
    case 4:
        to = "New York"; break;
    default:
        cout << "Invalid input";
        goto label2;
    }

    label3:
    cout << "Please select the day of departure:\n";
    cout << "1 for Monday\n2 for Tuesday\n3 for Wednesday\n4 for Thursday\n5 for Friday\n6 for Saturday\n7 for Sunday\n";
    cin >> day_num;
    switch(day_num)
    {
    case 1:
        day = "mo"; break;
    case 2:
        day = "tu"; break;
    case 3:
        day = "we"; break;
    case 4:
        day = "th"; break;
    case 5:
        day = "fr"; break;
    case 6:
        day = "sa"; break;
    case 7:
        day = "su"; break;
    default:
        cout << "Invalid input, please enter again.";
        goto label3;
    }

    flight flights[4] = {A1, A2, A3, A4};                                 //array of flight objects

    int flag = 0;                                                         //flag variable indicating whether one or more flights have been matched
    cout << "Here are some matches:\n";
    int flag_arr[4] = {0,0,0,0};
    for(int i = 0; i < 4; i++){
        int flag2 = flights[i].check_pref(from, to, day);
        if(flag2 == 1){
            flag_arr[i] = flights[i].id;
            flag = 1;
        }
    }
    if(flag == 0){                                                         //if no flights set the flag variable true
        cout << "\nNo flights were found matching your preferences. Please make a different selection.\n";
        goto label1;
    }

    label4:
    int choice = 0;
    cout << "Please enter your choice:";
    cin >> choice;
    flag = 0;
    for(int i = 0; i < 4; i++){
        if(choice == flag_arr[i]){
            flag = 1;
            break;
        }
    }
    if(flag == 0){
        cout << "\nInvalid selection. Please select again.\n";
        goto label4;
    }
    flights[choice - 1].book_ticket(name, day);

    flights[choice - 1].generate_ticket(name, day);
    }

The driver program obtains the user choices. After this it goes through an array of objects, checking if any of them match the user preferences by calling each flight object's internal function check_pref(). If a flight matches the user choices, it ses the flag variable to 1. If none of the flights match the user choices, the flag variable remains set to 0. In this case, the user is prompted to fill out the choices again in order to see some options.

After the user enters their choice of flight, that flight's internal functions for accommodating the user data and generating a ticket are called.

Demonstration

Given below is the passenger CSV file.


Now if I open the driver program and book a flight, there should a change in these records to reflect my booking.


The CSV file has been modified accordingly.

This shows that the system works as intended.

Choice of method of storing data:

The method described above with the CSV file works well if the file is not too large. But if the data is huge, more efficient ways are needed to store and retrieve the data. Because here, a file is read from, cleared, and then rewritten with the modifications. A database can be used for more efficient querying and editing of data. This project helps us learn about interfacing with a CSV file and how data can be prepared.

Source code:


#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

class flight
{
public:
    int id;
    flight(int x){                                          //constructor
        id = x;
    }

    int check_pref(char *from_d, char *to_d, char *day){              //internal function to check if the user preferences match with the flight properties
        vector<string> flight_props;
        string flight_line;
        flight_props.clear();

        ifstream properties("flight_objects_prop.csv");
        if(properties.is_open()){
            int current_line = 0;
            while(getline(properties, flight_line)){         //navigate to the line of the flight object
                current_line++;
                if(current_line - 1 == id){
                    break;
                }
            }
            stringstream ss(flight_line);                    //used to help split the line string into words
            string prop_word;
            while(getline(ss, prop_word, ',')){              //to store each column data of the row
                flight_props.push_back(prop_word);
            }

            if((flight_props[1] == from_d) && (flight_props[2] == to_d)){       //checking if the user preferences match with the flight properties
                for(int i = 4; i <= 10; i++){
                    if(flight_props[i] == day){
                        cout << "\nFlight " << flight_props[0] << " has been identified. Press " << id << " to select it.\n";
                        properties.close();
                        return 1;
                    }
                }
            }
            return 0;
        }
        else {
            cout << "Could not open CSV file.";
            return -1;
        }
    }

    void book_ticket(char *name, char *day){
        ifstream passengers_read("passengers.csv");             //file opened for reading
        string pass_names;
        vector<string> passengers;
        if(passengers_read.is_open()){
            while(getline(passengers_read, pass_names)){
                passengers.push_back(pass_names);                   //storing each line from csv file in a string vector
            }

            passengers_read.close();
        }
        else {
            cout << "\nCould not access passenger list.";
        }

        ofstream passengers_write("passengers.csv");             //file opened for writing

        if(passengers_write.is_open()){
            int name_line_number = id + (id - 1);
            int day_line_number = id + (id - 1) + 1;
            for(int i = 0; i < passengers.size(); i++){
                if(i == name_line_number - 1){
                    stringstream ss(passengers[i]);
                    string temp;
                    vector<string> temp_vector;
                    while(getline(ss, temp, ',')){
                        temp_vector.push_back(temp);
                    }
                    for(int i = 0; i < temp_vector.size(); i++){
                        if(temp_vector[i] == "0"){
                            temp_vector[i] = name;                      //replace zero with the passenger name
                            break;
                        }
                    }
                    string temp2;
                    for(int i = 0; i < temp_vector.size(); i++){
                        temp2 = temp2 + temp_vector[i] + ",";                 //combine all strings from the temp vector into a single string temp2
                    }

                    passengers_write << temp2 << "\n";                  //write the combined string temp2 to the csv file
                }
                else if(i == day_line_number - 1){
                    stringstream ss(passengers[i]);
                    string temp3;
                    vector<string> temp_vector3;
                    while(getline(ss, temp3, ',')){
                        temp_vector3.push_back(temp3);
                    }
                    for(int i = 0; i < temp_vector3.size(); i++){
                        if(temp_vector3[i] == "0"){
                            temp_vector3[i] = day;                      //replace zero with the day given by the passenger
                            break;
                        }
                    }
                    string temp4;
                    for(int i = 0; i < temp_vector3.size(); i++){
                        temp4 = temp4 + temp_vector3[i] + ",";                //combine all strings into one
                    }

                    passengers_write << temp4 << "\n";
                }
                else {
                    passengers_write << passengers[i] << "\n";            //skipping all other lines
                }                                                         //these lines are written back to the file as they were
            }
            passengers_write.close();
        }
        else{
            cout << "\nCould not access passenger list.";
        }
    }

    void generate_ticket(char *name, char *day){
        ifstream ticket("flight_objects_prop.csv");
        vector<string> details_lines;
        string line_string;
        if(ticket.is_open()){
            while(getline(ticket, line_string)){
                details_lines.push_back(line_string);                //obtaining the lines from csv file
            }
        }
        else{
            cout << "\nCould not open file.";
        }

        vector<string> details_main;
        string main_string;

        int current_line = 0;
        for(int i = 0; i < details_lines.size(); i++){
            current_line++;
            if(current_line - 1 == id){
                stringstream ss(details_lines[i]);
                while(getline(ss, main_string, ',')){
                    details_main.push_back(main_string);             //obtaining the line containing the required data
                }
            }
        }

        char *day_full;
        if(day == "mo"){
            day_full = "Monday";
        }
        else if(day == "tu"){
            day_full = "Tuesday";
        }
        else if(day == "we"){
            day_full = "Wednesday";               //obtaining the text to be displayed from user selected day
        }
        else if(day == "th"){
            day_full = "Thursday";
        }
        else if(day == "fr"){
            day_full = "Friday";
        }
        else if(day == "sa"){
            day_full = "Saturday";
        }
        else if(day == "su"){
            day_full = "Sunday";
        }

           //printing ticket after retrieving data from the CSV file
        cout << "---------------------------\n\n";
        cout << "Name: " << name;
        cout << "\nFrom: " << details_main[1] << "\tTo: " << details_main[2];
        cout << "\nFlight name: " << details_main[0];
        cout << "\nDay: " << day_full;
        cout << "\nTime: " << details_main[3];
        cout << "\n\n\tThank you for choosing to fly with us!";
    }
};

int main(){
    char name[15], *from, *to, *day;
    int from_num, to_num, day_num;

    flight A1(1), A2(2), A3(3), A4(4);                                      //flight objects declared

    cout << "\tWelcome to Random Airlines\n";
    cout << "---------------------------\n";

    cout << "Please enter your name: ";
    cin >> name;

    label1:
    cout << "\nPlease select departure city:\n";
    cout << "1 for Mumbai\n2 for New York\n3 for Dubai\n4 for Berlin\n";
    cin >> from_num;
    switch(from_num)
    {
    case 1:
        from = "Mumbai"; break;
    case 2:
        from = "New York"; break;
    case 3:
        from = "Dubai"; break;
    case 4:
        from = "Berlin"; break;
    default:
        cout << "Invalid input";
        goto label1;
    }

    label2:
    cout << "Please select city for arrival:\n";
    cout << "1 for Dubai\n2 for London\n3 for Mumbai\n4 for New York\n";
    cin >> to_num;
    switch(to_num)
    {
    case 1:
        to = "Dubai"; break;
    case 2:
        to = "London"; break;
    case 3:
        to = "Mumbai"; break;
    case 4:
        to = "New York"; break;
    default:
        cout << "Invalid input";
        goto label2;
    }

    label3:
    cout << "Please select the day of departure:\n";
    cout << "1 for Monday\n2 for Tuesday\n3 for Wednesday\n4 for Thursday\n5 for Friday\n6 for Saturday\n7 for Sunday\n";
    cin >> day_num;
    switch(day_num)
    {
    case 1:
        day = "mo"; break;
    case 2:
        day = "tu"; break;
    case 3:
        day = "we"; break;
    case 4:
        day = "th"; break;
    case 5:
        day = "fr"; break;
    case 6:
        day = "sa"; break;
    case 7:
        day = "su"; break;
    default:
        cout << "Invalid input, please enter again.";
        goto label3;
    }

    flight flights[4] = {A1, A2, A3, A4};                                 //array of flight objects

    int flag = 0;                                                         //flag variable indicating whether one or more flights have been matched
    cout << "Here are some matches:\n";
    int flag_arr[4] = {0,0,0,0};
    for(int i = 0; i < 4; i++){
        int flag2 = flights[i].check_pref(from, to, day);
        if(flag2 == 1){
            flag_arr[i] = flights[i].id;
            flag = 1;
        }
    }
    if(flag == 0){                                                         //if no flights set the flag variable true
        cout << "\nNo flights were found matching your preferences. Please make a different selection.\n";
        goto label1;
    }

    label4:
    int choice = 0;
    cout << "Please enter your choice:";
    cin >> choice;
    flag = 0;
    for(int i = 0; i < 4; i++){
        if(choice == flag_arr[i]){
            flag = 1;
            break;
        }
    }
    if(flag == 0){
        cout << "\nInvalid selection. Please select again.\n";
        goto label4;
    }
    flights[choice - 1].book_ticket(name, day);

    flights[choice - 1].generate_ticket(name, day);
    }

Comments

Popular posts from this blog

Flight booking system in C++

An implementation of a linked list in Java