reading text file in c++

Hi,

I have a text file & it is having content as
2|50000|1000|S|Abc|0
I would like to read the above file and assign values to six variables: integer and string.

Here, I am using C++ and solaris is the Operating system.
Please tell me like how to do that in C++?

thanks,
shankarraj
shankarrajAsked:
Who is Participating?
 
evilrixConnect With a Mentor Senior Software Engineer (Avast)Commented:
Fully working example.
//  Required for std::stringstream
#include <sstream>
 
// Required for for_each()
#include <algorithm>
 
// Required for std::istream
#include <iostream>
 
// Required for std::vector
#include <vector>
 
// Data -- POD type (this could also be a proper class!)
struct Data
{
	int field1;
	int field2;
	int field3;
	char field4;
	std::string field5;
	int field6;
};
 
// Overloaded input stream operator
std::istream & operator >> (std::istream & is, Data & data)
{
	std::string line;
	getline(is, line);
 
	if(is.good())
	{
		std::string::size_type pos = 0;
		std::string::size_type lpos = 0;
 
		int const LAST_FIELD = 6;
 
		for(int field = 0 ; field < LAST_FIELD ; ++ field)
		{
 
			// Find end of field
			if(std::string::npos == (pos = line.find('|', lpos)))
			{
				// If not found and last field use size
				if((LAST_FIELD - 1) == field)
				{
					pos = line.size();
				}
				else // If not last field we have an error condition
				{
					throw std::runtime_error("Invalid record structure");
				}
			}
 
			// Use to convert to the required data type
			std::stringstream ssField(line.substr(lpos, (pos - lpos)));
 
			// Start of next field
			lpos = pos + 1;
 
			// Extract field
			switch(field)
			{
			case 0:
				ssField >> data.field1;
				break;
			case 1:
				ssField >> data.field2;
				break;
			case 2:
				ssField >> data.field3;
				break;
			case 3:
				ssField >> data.field4;
				break;
			case 4:
				ssField >> data.field5;
				break;
			case 5:
				ssField >> data.field6;
				break;
			default:
				// We should never get here!
				throw std::runtime_error("Invalid record size");
				break;
			}
		}
	}
 
	return is;
}
 
// Typedef to make code more readable
typedef std::vector<Data> DataVector;
 
// Processes stream and builds a vector of records
void ProcessStream(std::istream & is, DataVector & dv)
{
	for(;;)
	{
		// Create new data structure
		Data data = {0};
 
		// Stream out next record
		is >> data ;
 
		// Process file until EOF or error
		if(is.eof()) { break; }
		if(is.bad()) { throw std::runtime_error("Error. Bad file stream."); }
 
		// Store record in vector
		dv.push_back(data);
	}
}
 
// Output functor (just for demo purposes)
class OutputResult
{
public:
	OutputResult(): m_nRecCnt(0){}
	void operator()(Data const & data)
	{
		++ m_nRecCnt;
		std::cout
			<< "Record: " << m_nRecCnt << std::endl
			<< "- Field1: " << data.field1 << std::endl
			<< "- Field2: " << data.field2 << std::endl
			<< "- Field3: " << data.field3 << std::endl
			<< "- Field4: " << data.field4 << std::endl
			<< "- Field5: " << data.field5 << std::endl
			<< "- Field6: " << data.field6 << std::endl
			<< std::endl;
	}
private:
	int m_nRecCnt;
};
 
int main()
{
	// Test data (this can be from an ifstream -- e.g. ifstream testdata("testdata.txt"))
	std::stringstream testdata (
		"1|50000|1000|S|Abc|0\n"
		"2|50001|1001|T|Def|1\n"
		"3|50002|1002|U|Ghi|2\n"
		"4|50003|1003|V|Jkl|3\n"
		"5|50003|1004|W|Mno|4\n"
		"6|50003|1005|X|Pqr|5\n"
		"7|50003|1006|Y|Stu|6\n"
	);
 
	// Data will be read into this vector
	DataVector dv;
 
	// Process data from stream
	ProcessStream(testdata, dv);
 
	// Output records in vector
	std::for_each(dv.begin(), dv.end(), OutputResult());
 
	return 0;
}

Open in new window

0
 
Infinity08Connect With a Mentor Commented:
Here's a good introduction to I/O with files in C++ :

        http://www.cplusplus.com/doc/tutorial/files.html


An easy way would be to use getline to read a line from the file :

        http://www.cplusplus.com/reference/string/getline.html

and then use string operations (substr, find) to extract the tokens from the line :

        http://www.cplusplus.com/reference/string/string/find.html
        http://www.cplusplus.com/reference/string/string/substr.html
0
 
Deepu AbrahamConnect With a Mentor R & D Engineering ManagerCommented:
For pipe delimited files
http://www.augustcouncil.com/~tgibson/tutorial/iotips.html
This may as well help you.
Best Regards,
DeepuAbrahamK
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
rstaveleyConnect With a Mentor Commented:
A combination of getline and extraction on an istringstream does the trick nicely with this sort of thing. Experience says don't do it directly with the ifstream, because one bad line thrhows it all out of kilter otherwise.

The not-so-secret weapon here is using '|' as the delimiter to getline.
#include <fstream>
#include <sstream>
#include <iostream>
 
int main()
{
	std::ifstream fin("x.dat");
	std::string str;
	while (getline(fin,str)) {
		std::istringstream istr(str);
 
		// For the likes of "2|50000|1000|S|Abc|0"
		std::string str1,str2;
		int i1,i2,i3,i4;
		char junk;
 
		if (
			(istr >> i1) && (istr >> junk) && (junk == '|')
		&&	(istr >> i2) && (istr >> junk) && (junk == '|')
		&&	(istr >> i3) && (istr >> junk) && (junk == '|')
		&&	getline(istr,str1,'|')
		&&	getline(istr,str2,'|')
		&&	(istr >> i4) /*&& (istr >> junk) && (junk == '|')*/
		) {
			std::cout << i1 << '|' << i2 << '|' << i3 << '|' << str1 << '|' << str2 << '|' << i4 << '\n';
		}
	}
}

Open in new window

0
 
itsmeandnobodyelseConnect With a Mentor Commented:
You can read the file with

#include <fstream>
#include <string>
using namespace std;

       

        ifstream  file("file.dat");
        string line;
        while (getline(file, line))
        {
             ...
        }
        file.close();


That reads the file line by line.

For the ...

you should parse the string line like that:

     line += '|';   // add a final delimiter
     int pos = 0;
     int lpos = 0;
     int nitem = 0;
     while ((pos = (int)line.find('|', lpos)) != string::npos)
     {
            string item = line.substr(pos, lpos - pos);
            ...
            nitem++;
            lpos = pos + 1;
     }


Put the following below includes and above all code or in a header file:

#include <sstream>

enum { FLD0, FLD1 , FLD2, FLD3, FLD4, FLD5, FLD_MAX };

struct Record
{
     int ifld0;
     int ifld1;
     int ifld2;
     char cfld3;
     string sfld4;
     int ifld5;
     
};
 
For the ...  you may evaluate the columns like taht:

          Record rec;
          switch(nitem)
          {
              case FLD0:  
              {
                     istringstream iss(item);
                     if (!iss >> rec.ifld0)
                     {
                             cout << "wrong item " << item << endl;
                             return;
                     }
               }
               break;
              case FLD1:  
              {
                     // dito to FLD0
              }
              break;
              ...
              case FLD3:  
              {
                     if (item.length() != 1)
                     {
                             cout << "wrong item " << item << endl;
                             return;
                     }
                     rec.cfld3 = item[i];
               }
               break;
              case FLD4:   rec.sfld4 = item; break;
              case FLD5:  
              {
                     // dito to FLD0
              }
                 
          }
          ...

Finally you  have to store the Record rec to some container and array. I would suggest

   std::vector<Record> records;

Then the ... would be


       records.push_back(rec);


Regards, Alex


         

0
 
Infinity08Commented:
Heh ... as usual, you're more elaborate in your replies than me, Alex ... ;)
0
 
itsmeandnobodyelseCommented:
>>>> you're more elaborate in your replies than me, Alex ...

'elaborate' ??? you mean chatty?

Rob, only needs one third of that I needed ... most likely you'll get the points ... oh the world is bad ...
0
 
Infinity08Commented:
>> 'elaborate' ??? you mean chatty?

http://www.merriam-webster.com/dictionary/elaborate    ;)

That was a compliment btw !!
0
 
itsmeandnobodyelseCommented:
I like the Latin 'elaboratus'  ;-)

0
 
rstaveleyCommented:
There is nothing wrong with a good chat, lubricated of course by an excellent Belgian beer.

Infinity08, do you get an "Attach beer snippet" checkbox in your locale? 8-)
0
 
Infinity08Commented:
>> Infinity08, do you get an "Attach beer snippet" checkbox in your locale? 8-)

I wish ... I would probably add a good Rochefort 8 trappist beer (one of my favorite Belgian beers) :) Mmm ... with a bit of cheese on the side, it's just perfect heh
0
 
itsmeandnobodyelseCommented:
>>>> by an excellent Belgian beer.
it is 'perfumed', isn't it? Did you never hear of 'beer purity law' ?

BTW, I have draft beer (Philipps system 6 liters, mostly with Becks) in my home bureau. Nearly as good as a checkbox and much more real ;-)  The only problem is that I am 'on the road' from Monday to Thursday ...
0
 
Infinity08Commented:
>> id you never hear of 'beer purity law' ?

No, but a short look on the internet reveals that the ingredients of beer can only be barley, hops and water. That's quite limiting, and doesn't permit "alive" beer, since you can't use yeast ... it also doesn't include sugar which is commonly used for the "good" beers.

These are the 5 ingredients of a Rochefort trappist beer : water, hops, barley, yeast and sugar.
0
 
rstaveleyCommented:
It's liquid bread really. I'll look out for Rochefort. I'm still a Trappist newbie, but eager to learn more.
0
 
rstaveleyCommented:
Here's my general solution (religion/culture permitting):
not_so_std::beerstream beer("Rochefort");
while (beer >> rstaveley >> Infinity08 >> itsemeandnobodyelse)
    ;

Open in new window

0
 
rstaveleyCommented:
Hmmm... I think Infinity08 had too much, he got syntax highlighted!
0
 
Infinity08Commented:
Why do you get served first ? lol

On the upside, my name is in purple ... hehe
0
 
itsmeandnobodyelseCommented:
>>>> yeast
Actually there is no beer without yeast. But they didn't mention it in the law (most likely they didn't want to confuse the customers?)

>>>> sugar
Brrrrrrrrr. Didn't I say it it is 'perfumed'. Ever heard that a 'real' man drinks sweet beer?

>>>> Why do you get served first ? lol
You can get my share. I've heard the dregs contain most of the sugar....
0
 
Infinity08Commented:
>> >>>> sugar
>> Brrrrrrrrr. Didn't I say it it is 'perfumed'. Ever heard that a 'real' man drinks sweet beer?

Oh, but the beer is not sweet. The sugar is converted to alcohol, and is added to have a higher alcohol percentage. The Rochefort 8 I mentioned for example is about 9% alcohol. I've drank beers upto 15% in Belgium.
0
 
rstaveleyCommented:
> I've drank beers upto 15% in Belgium.

That's enough to make you go purple.
0
 
Infinity08Commented:
lol
0
 
itsmeandnobodyelseCommented:
> I've drank beers upto 15% in Belgium.
I've drunk (bock) beer up to 21% ... of course ... no sugar

>>>> That's enough to make you go purple
When lying under the table the colors don't matter ;-)

BTW, I am at home today but I've to wait until noon (f...ing principles) before I get my first beer ...
0
 
Infinity08Commented:
>> I've drunk (bock) beer up to 21%

Wow ... never heard of a Bock with that much alcohol ... must have been some special brew ...
0
 
rstaveleyCommented:
> I've to wait until noon

"I like a good beer buzz early in the morning..." (S. Crow)
0
 
itsmeandnobodyelseCommented:
0
 
rstaveleyCommented:
I think shankarraj has given up on us in despair.
0
 
evilrixSenior Software Engineer (Avast)Commented:
If you want to catch and explicitly report the thrown exceptions change main to be like this...
int main()
{
	int nRetval = 0;
 
	try
	{
		// Test data (this can be from an ifstream -- e.g. ifstream testdata("testdata.txt"))
		std::stringstream testdata (
			"1|50000|1000|S|Abc|0\n"
			"2|50001|1001|T|Def|1\n"
			"3|50002|1002|U|Ghi|2\n"
			"4|50003|1003|V|Jkl|3\n"
			"5|50003|1004|W|Mno|4\n"
			"6|50003|1005|X|Pqr|5\n"
			"7|50003|1006|Y|Stu|6\n"
		);
 
		// Data will be read into this vector
		DataVector dv;
 
		// Process data from stream
		ProcessStream(testdata, dv);
 
		// Output records in vector
		std::for_each(dv.begin(), dv.end(), OutputResult());
	}
	catch(std::exception const & ex)
	{
		std::cerr << ex.what();
		nRetval = -1;
	}
 
	return nRetval;
}

Open in new window

0
 
SJT2003ACommented:
OK, check the following code. It is a simple example of reading a text file which contains of fields of any type (ie, string, non-string) with | (pipe) delimited.  
The sField is a string stores any type where as nField stores only numberic fields. Just uncomment the commented lines to read from a file.

Check it out. Good luck :)

#include "stdafx.h"
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>

using namespace std;

int main()
{
      string line("123|Samson|262|345 Blvd|North York|L9T 5Y3");
      //ifstream ifstr("mydata.dat");
      istringstream istr;
      string alphabetic("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
      string numeric("1234567890");
      string sField;
      long nField;
      string str;
      int pos, lpos;
      //if (!ifstr) {
      //      cout << "file open error " << endl;
      //      exit(1);
      //}

      //while (getline(ifstr,line)) {  //add this line if it is for a file read
            lpos = 0;
            do {
                  pos = line.find_first_of("|",lpos);
                  str = line.substr(lpos, (pos-lpos));
                  if ( (int(str.find_first_of(alphabetic)) >= 0 && int(str.find_first_of(numeric)) >= 0) || //alphanumeric
                        (int(str.find_first_of(alphabetic)) >= 0) ) { //alphabetic
                        sField = str;
                        cout << sField << endl;
                  }
                  else if (int(str.find_first_of(numeric)) >= 0) { //numeric
                        istr.str(str);
                        istr >> nField;
                        cout << nField << endl;
                        istr.clear();
                  }
                  else { //special chars
                        sField = str;
                        cout << sField << endl;
                  }
                  lpos = pos+1;
            } while (pos >= 0);

      //} //while

      return 0;
}

The output is as follows:

123
Samson
262
345 Blvd
North York
L9T 5Y3
Press any key to continue

 
0
 
SeanDurkinCommented:
No comment has been added to this question in more than 21 days, so it is now classified as abandoned.

I will leave the following recommendation for this question in the Cleanup Zone:
      Split: rstaveley {http:#20334000} & Infinity08 {http:#20333741} & DeepuAbrahamK {http:#20333794} & itsmeandnobodyelse {http:#20334030} & evilrix {http:#20345750}

Any objections should be posted here in the next 4 days. After that time, the question will be closed.

Sean
EE Cleanup Volunteer
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.