AFAIK, there is nothing that would make it out of the box. But you have all the tools for creating it yourself.
Path C
You read the lines in char * (with cin.getline() ) and then use strtok and strcpy
Getline method
The getline function takes a third parameter to specify the delimiter. You can use this to split the line into istringstream . Sort of:
int main() { std::string line, temp; std::ifstream myfile("file.txt"); std::getline(myfile, line); while (myfile.good()) { empdata data; std::getline(myfile, line); if (myfile.eof()) { break; } std::istringstream istr(line); std::getline(istr, temp, '|'); data.sl = ::strtol(temp.c_str(), NULL, 10); std::getline(istr, temp, '|'); data.empNO = ::strtol(temp.c_str(), NULL, 10); istr.getline(data.name, sizeof(data.name), '|'); istr.getline(data.department, sizeof(data.department), '|'); istr.getline(data.band, sizeof(data.band), '|'); istr.getline(data.location, sizeof(data.location), '|'); } return 0; }
This is the C ++ version of the previous version.
Search method
You read the lines in the line (as you do now) and use string::find(char sep, size_t pos) to find the next origin of the delimiter and copy the data (from the string :: c_str ()) between the beginning of the substring and the delimiter to your fields
Manual way
You just iterate over the string. If the character is a delimiter, you put NULL at the end of the current field and move on to the next field. In addition, you simply write a character at the current position of the current field.
What to choose?
If you are more used to one of them, stick to it.
That's just my opinion.
The getline path will be the easiest to code and support.
The search method is medium. It is still at a fairly high level and avoids using istringstream .
The manual method will be really low, so you need to structure it to make it serviceable. For example, you may have an explicit description of the lines as an array of fields with the maximum size and current position. And since you have both int and char [], this will be tricky. But you can easily customize it the way you want. For example, your code only allows 20 characters for the department field, while Research and Development on line 2 is longer. Without special processing, the getline path will leave istringstream in a bad state and will not read anything else. And even if you clear the state, you will be in a bad mood. Therefore, you must first read std::string , and then copy the beginning to the char * field.
The following is a work instruction:
class Field { public: virtual void reset() = 0; virtual void add(empdata& data, char c) = 0; }; class IField: public Field { private: int (empdata::*data_field); bool ok; public: IField(int (empdata::*field)): data_field(field) { ok = true; reset(); } void reset() { ok = true; } void add(empdata& data, char c); }; void IField::add(empdata& data, char c) { if (ok) { if ((c >= '0') && (c <= '9')) { data.*data_field = data.*data_field * 10 + (c - '0'); } else { ok = false; } } } class CField: public Field { private: char (empdata::*data_field); size_t current_pos; size_t size; public: CField(char (empdata::*field), size_t size): data_field(field), size(size) { reset(); } void reset() { current_pos = 0; } void add(empdata& data, char c); }; void CField::add(empdata& data, char c) { if (current_pos < size) { char *ix = &(data.*data_field); ix[current_pos ++] = c; if (current_pos == size) { ix[size -1] = '\0'; current_pos +=1; } } } int main() { std::string line, temp; std::ifstream myfile("file.txt"); Field* fields[] = { new IField(&empdata::sl), new IField(&empdata::empNO), new CField(reinterpret_cast<char empdata::*>(&empdata::name), 20), new CField(reinterpret_cast<char empdata::*>(&empdata::department), 20), new CField(reinterpret_cast<char empdata::*>(&empdata::band), 3), new CField(reinterpret_cast<char empdata::*>(&empdata::location), 20), NULL }; std::getline(myfile, line); while (myfile.good()) { Field** f = fields; empdata data = {0}; std::getline(myfile, line); if (myfile.eof()) { break; } for (std::string::const_iterator it = line.begin(); it != line.end(); it++) { char c; c = *it; if (c == '|') { f += 1; if (*f == NULL) { continue; } (*f)->reset(); } else { (*f)->add(data, c); } }
It is direct, reliable, efficient, and maintainable: adding a field is simple and tolerant of errors in the input file. But this is not like the others, and this will require much more tests. Therefore, I do not recommend using it without special reasons (the need to accept several separators, optional fields and a dynamic order, ...)