Using ifstream to read in multiple files within a loop

I have written the following code to read in a number of files and to extract data and place in new file where data is grouped by a different identifier.

The code compiles fine and does not produce any errors during runtime. However there is a bug where the first file read in will load correctly and all lines in the file will be placed in the relevant output files. But for all other files read in after the initial first file no records are loaded. The record count is always zero for these files.

I am not completely familiar with C++ and I do not know what to do to get this to work for reading the contents all files within the loop.

Can someone give me a pointer?

Thanks

nt main () {
    dataReader d;
    string file, ofile, fpre, fsuf, no, ofpre, user, line, beg;
    fpre = "file_";
    ofpre ="obj_"; 
    fsuf = ".txt";
    char delim[]=",";
    char *str;
    char *token;
    int records = 0;
    ifstream myfile;
    ofstream outfile;
    for (int i = 2; i < 10; i++)
    {
        no = fpre + d.zerofill(i,5);
        file = no + fsuf;
        cout << file.c_str() << endl;
        myfile.open(file.c_str());
        //myfile.seekg(ios_base::beg);
        beg = "";
        if (myfile.is_open())
        {
           getline (myfile,beg);
           cout << beg << endl;
           records = 0;
           cout << "Reading file " << i << ": ";
           while (! myfile.eof() )
           {
                 getline (myfile,line);
                 if (line != "") 
                 {
                    records++;
                    str=new char[line.length() + 1];  
                    strncpy(str, line.c_str(), (line.length() + 1));
                    
                    token=strtok(str, delim);
                    user= string(token);
                    ofile = ofpre + user + fsuf;
                    outfile.open(ofile.c_str(), ios::app);
                    outfile << i;
                    //In subsequent calls to strtok, the first argument is NULL
                    while((token=strtok(NULL, delim))!=NULL)
                    {
                       outfile << "," << token;
                       }
                    outfile << endl;
                    outfile.close();
                 }
           }
           cout << records << " loaded. " << endl;
           myfile.close();
        }
        else cout << "Unable to open file"; 
    }
    cout << "Process Complete" << endl;
  return 0;  
}

Open in new window

Gordy1984Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jkrCommented:
Apart from the problem you are having (which I so far haven't spotted in your code), there are other glitches:
                 if (line != "") 
                 {
                    records++;
                    str=new char[line.length() + 1];  
                    strncpy(str, line.c_str(), (line.length() + 1));
                    
                    token=strtok(str, delim);
                    user= string(token);
                    ofile = ofpre + user + fsuf;
                    outfile.open(ofile.c_str(), ios::app);
                    outfile << i;
                    //In subsequent calls to strtok, the first argument is NULL
                    while((token=strtok(NULL, delim))!=NULL)
                    {
                       outfile << "," << token;
                       }
                    outfile << endl;
                    outfile.close();
                    delete [] str; // <----------- missing
                 }

Open in new window

0
evilrixSenior Software Engineer (Avast)Commented:
After the first file has been processed the EOF flag on myfile will be set. Although you close the file and reopen it the EOF flag will still be set. You need to clear the status flags each iteration of the loop using myfile.clear() just before line 18 where you open it. This will ensure you are starting with a file that is in a 'as new' state.

http://www.cplusplus.com/reference/iostream/ios/clear.html
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Infinity08Commented:
Or, easier : place this line inside the for loop :

        ifstream myfile;

(as the first line in the for loop)
0
Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

Deepu AbrahamR & D Engineering ManagerCommented:
main () {
    dataReader d;
    string ofile, fpre, fsuf, no, ofpre, user, line, beg; <-------------------- removed variable file from here
    fpre = "file_";
    ofpre ="obj_";
    fsuf = ".txt";
    char delim[]=",";
    char *str;
    char *token;
    int records = 0;
    ifstream myfile;
    ofstream outfile;
    for (int i = 2; i < 10; i++)
    {
        string file; <---------------Added the variable file here
        .....

Hope this helps, seems like the the string file is not getting populated properly.

or else you can keep the same code but initialise the file in the loop with  empty ("")

eg:

  for (int i = 2; i < 10; i++)
    {
        file=""; <--------------- Initialise here
        .....

Best Regards,
DeepuAbrahamK

0
evilrixSenior Software Engineer (Avast)Commented:
>> Or, easier : place this line inside the for loop
Easier? Different maybe, not necessarily easier.
0
evilrixSenior Software Engineer (Avast)Commented:
...although I will conceded this is written very much like a C program (with all vars declared at the top) and this is not the way I'd do this (define vars at the point they are required).
0
Infinity08Commented:
>> >> Or, easier : place this line inside the for loop
>> Easier? Different maybe, not necessarily easier.

With easier I meant that you don't have to care about clearing the flags (so you can't forget either). You just create a new stream. As you said : in C++ it's common to create objects the moment they're needed, and not sooner.
0
rstaveleyCommented:
I agree that it is easier to put this inside the loop. You can also wave good-bye to close, because the dtor does the right thing. Scope does nice things with automatic objects.

strtok is a nasty function from the C library. There ought to be "C Programmers Anonymous" meetings for C++ programmers who can't shake the habit. Consider using istringstream with getline and ','. You can use it with the extraction operator nicely. Again, it is an object that works nicely with scope.
#include <iostream>
#include <iomanip>
//#include <locale>
#include <sstream>
 
int main()
{
	std::istringstream istr("PI,3.142,A useful constant");
	//istr.imbue(std::locale("en_US"));
 
	std::string name,description;
	double pi;
	char junk;
	if (getline(istr,name,',') && (istr >> pi >> junk) && junk == ',' && getline(istr,description,','))
		std::cout << "The value of " << name << " is " << std::setprecision(4) << pi << " and it is known as '" << description << "'\n";
	else
		std::cout << "Oo-err\n";
}

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.