Search code examples
c++file-iorecord

Write and read records to .dat file C++


I am quite new to C++ and am trying to work out how to write a record in the format of this structure below to a text file:

struct user {
    int id;
    char username [20];
    char password [20];
    char name [20];
    char email [30];
    int telephone;
    char address [70];
    int level;
}; 

So far, I'm able to write to it fine but without an incremented id number as I don't know how to work out the number of records so the file looks something like this after I've written the data to the file.

1 Nick pass Nick email tele address 1
1 user pass name email tele address 1
1 test test test test test test 1
1 user pass Nick email tele addy 1
1 nbao pass Nick email tele 207 1

Using the following code:

ofstream outFile;

outFile.open("users.dat", ios::app);

// User input of data here

outFile << "\n" << 1 << " " << username << " " << password << " " << name << " "
        << email << " " << telephone << " " << address  << " " << 1;
cout << "\nUser added successfully\n\n";

outFile.close();

So, how can I increment the value for each record on insertion and how then target a specific record in the file?

EDIT: I've got as far as being able to display each line:

  if (inFile.is_open())
    {
    while(!inFile.eof())
    {

    cout<<endl;
    getline(inFile,line);
    cout<<line<<endl;

    }
    inFile.close();
    }

Solution

  • What you have so far is not bad, except that it cannot handle cases where there is space in your strings (for example in address!)

    What you are trying to do is write a very basic data base. You require three operations that need to be implemented separately (although intertwining them may give you better performance in certain cases, but I'm sure that's not your concern here).

    • Insert: You already have this implemented. Only thing you might want to change is the " " to "\n". This way, every field of the struct is in a new line and your problem with spaces are resolved. Later when reading, you need to read line by line
    • Search: To search, you need to open the file, read struct by struct (which itself consists of reading many lines corresponding to your struct fields) and identifying the entities of your interest. What to do with them is another issue, but simplest case would be to return the list of matching entities in an array (or vector).
    • Delete: This is similar to search, except you have to rewrite the file. What you do is basically, again read struct by struct, see which ones match your criteria of deletion. You ignore those that match, and write (like the insert part) the rest to another file. Afterwards, you can replace the original file with the new file.

    Here is a pseudo-code:

    Write-entity(user &u, ofstream &fout)
        fout << u.id << endl
             << u.username << endl
             << u.password << endl
             << ...
    
    Read-entity(user &u, ifstream &fin)
         char ignore_new_line
         fin >> u.id >> ignore_new_line
         fin.getline(u.username, 20);
         fin.getline(u.password, 20);
         ...
         if end of file
             return fail
    
    Insert(user &u)
         ofstream fout("db.dat");
         Write-entity(u, fout);
         fout.close();
    
    Search(char *username) /* for example */
         ifstream fin("db.dat");
         user u;
         vector<user> results;
         while (Read-entity(u))
             if (strcmp(username, u.username) == 0)
                 results.push_back(u);
         fin.close();
         return results;
    
    Delete(int level) /* for example */
         ifstream fin("db.dat");
         ofstream fout("db_temp.dat");
         user u;
         while (Read-entity(u))
             if (level != u.level)
                 Write-entity(u, fout);
         fin.close();
         fout.close();
         copy "db_temp.dat" to "db.dat"
    

    Side note: It's a good idea to place the \n after data has been written (so that your text file would end in a new line)