0

I'm looking for a way to find the number of items in a .txt file.

The file structure is as follows:

students.txt pricem 1441912123
house.pdf jatkins 1442000124
users.txt kevin_tomlinson 1442001032
accounts.mdb kevin_tomlinson 1442210121
vacation.jpg smitty83 1442300125
calendar.cpp burtons 1442588012

The result should be 18 in this example since there are 18 separate "words" in this file.

I need that value so I can iterate through the items and assign them to an array of structures (maybe there's a way to accomplish both of these steps together?):

// my structure
struct AccessRecord
{
   string filename;
   string username;
   long timestamp;
};

// new instance of AccessRecord
// max possible records: 500
AccessRecord logRecords[500];

// while file has content
while (!fin.eof())
{
   // loop through file until end
   // max possible records: 500
   for (int i = 0; i < 500; i++) // need to figure out how to iterate
   {
      fin >> logRecords[i].filename
          >> logRecords[i].username
          >> logRecords[i].timestamp;
   }
}

Which will then be written to the screen.

So the question is, how do I find the count? Or is there a better way?

Rakete1111
  • 42,521
  • 11
  • 108
  • 141
Scott
  • 1,209
  • 15
  • 22
  • Recommended reading: [Why is iostream::eof inside a loop condition considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – user4581301 May 04 '18 at 18:32

2 Answers2

2

You know that each line contains a string, a string and a long, so you can iterate with:

std::vector<AccessRecord> logs;
std::string fname, uname;
long tstamp;
while(fin >> fname >> uname >> tstamp) {
    logs.push_back(AccessRecord(fname, uname, tstamp));
    //To avoid copies, use: (thanks @Rakete1111!)
    //logs.emplace_back(std::move(fname), std::move(uname), tstamp);
}

This is assuming you've created a constructor for your struct like:

AccessRecord(std::string f, std::string u, long t)
               : filename(f), username(u), timestamp(t) { }

Notice that I'm using an std::vector here instead of an array so that we don't even have to worry about the number of items, since the vector will resize itself dynamically!

scohe001
  • 13,879
  • 2
  • 28
  • 47
  • You can remove that `new_log` by using `emplace_back`: `logs.emplace_back(std::move(fname), std::move(uname), tstamp);` + moves to avoid copies :) – Rakete1111 May 04 '18 at 18:04
  • Thanks, @scohe001. This is for school. We haven't learned about constructors or vectors yet. I think it might raise some eyebrows if I used this approach, not that I understand it anyway :) – Scott May 04 '18 at 18:06
  • @Rakete1111 not too familiar with `emplace_back` so I've left it as a comment. Thanks for the suggestion! – scohe001 May 04 '18 at 18:07
  • @scohe001 Well then you should get familiar with it :) It's really great :D – Rakete1111 May 04 '18 at 18:08
  • Yeah. Definitely will. I think those concepts are coming up in later chapters. – Scott May 04 '18 at 18:23
0

You should overload operator>> for your structure:

struct AccessRecord
{
   string filename;
   string username;
   long timestamp;
   friend std::istream& operator>>(std::istream& input, AccessRecord& ar);
};

std::istream& operator>>(std::istream& input, AccessRecord& ar)
{
   input >> ar.filename;
   input >> ar.username;
   input >> ar.timestamp;
   return input;
}

This allows you to simplify your input function:

AccessRecord ar;
std::vector<AccessRecord> logs;
//...
while (fin >> ar)
{
  database.push_back(ar);
}

Usually, if you are accessing an objects data members directly outside of the class or structure, something is wrong. Search the internet for "data hiding", "c++ encapsulation" and "c++ loose coupling".

Thomas Matthews
  • 52,985
  • 12
  • 85
  • 144