Thread: Using 1 ofstream variable to write multiple output files

  1. #1
    Registered User
    Join Date
    Mar 2012
    Location
    AL, USA
    Posts
    2

    Question Using 1 ofstream variable to write multiple output files

    Greeting everyone,

    Before you read, I've posted all of the code in the program in case someone wanted to see exactly what I was doing, but the main area I'm having issues with is writing to outFile in the writeOutputFile function.

    I'm attempting to write a simple find and replace program. There are 2 input files, small.txt and array.txt, and the number of output files is based upon the number of rows in array.txt.

    small.txt is the template file that I would like to search through and then replace with the (partially) user defined string.

    array.txt is really a CSV file with 2 columns: TariffID and TariffServiceCode
    Ex.)
    12345,ABC
    23456,BCD
    34567,CDE

    The program searches the template file (small.txt) line by line and replaces the string "<TariffID>YYYYY</TariffID>" or "<TariffServiceCode>ZZZZZ</TariffServiceCode>" with a similar string, except YYYYY and ZZZZZ are different. YYYYY and ZZZZZ correspond to the list of values in array.txt. After each line, whether it was replaced or not, it is then written to an output file. Each output file has the YYYYY portion of the CSV file prepended to the filename supplied by the user.

    So far, all of the find and replace functionality works (but yes, does look messy). The issue I'm having is when I run the program, the first output file has the correct data in it (including the replaced text) along with the correct filename, but the second file and after have the correct filenames but are blank inside.

    Code:
    #include<iostream>
    #include<fstream>
    #include<string>
    //#include<sstream>
    
    using namespace std;
    
    //#define
    
    //Globals
    ifstream inFile;
    ifstream arrayFile;
    ofstream outFile;
    
    string tariffID;
    string longTariffID;
    string tariffServiceCode;
    string longTariffServiceCode;
    
    //prototypes
    void writeOutputFile(string&, string, string, string, string, int, int);
    
    int main()
    {
        int lengthLongTariffID = 0;
        int lengthLongTariffServiceCode = 0;
    
        string arrayFileString;
        string arrayFileTariffID;
        string arrayFileLongTariffID;
        string arrayFileTariffServiceCode;
        string arrayFileLongTariffServiceCode;
    
        string filename;
        string filenameTariffID;
        string lastFilenameTariffID = "";
    
        size_t found;
        int foundINT;
    
        size_t lengthOldTariffID;
        int INTlengthOldTariffID;
    
        size_t lengthOldTariffServiceCode;
        int INTlengthOldTariffServiceCode;
    
        int x;
        int y;
    
        inFile.open("small.txt");
        arrayFile.open("array.txt");
    
        cout << "\n\nWhat do you want the filename of the output to be?\nPlease use underscores instead of spaces and include the file extension (.txt):  ";
        cin >> filename;
    
        cout << "What is the Tariff ID you want to change?:  ";
        cin >> tariffID;
        lengthOldTariffID = tariffID.length();
        INTlengthOldTariffID = int(lengthOldTariffID);
    
        cout << "What is the Tariff Service Code you want to change? (Capitalization counts):  ";
        cin >> tariffServiceCode;
        lengthOldTariffServiceCode = tariffServiceCode.length();
        INTlengthOldTariffServiceCode = int(lengthOldTariffServiceCode);
    
        longTariffID = "<TariffID>" + tariffID + "</TariffID>";
        longTariffServiceCode = "<TariffServiceCode>" + tariffServiceCode + "</TariffServiceCode>";
    
        //Length of "<TariffID>" = 10 and Length of "</TariffID>" = 11
        lengthLongTariffID = 10 + INTlengthOldTariffID + 11;
        //Length of "<TariffServiceCode>" = 19 and Length of "</TariffServiceCode>" = 20
        lengthLongTariffServiceCode = 19 + INTlengthOldTariffServiceCode + 20;
    
        while( getline(arrayFile, arrayFileString) )
        {
            found = arrayFileString.find(",");
            foundINT = int(found);
    
            //Builds arrayFileLongTariffID from arrayFile to compare to longTariffID
            arrayFileLongTariffID = "<TariffID>";
            for (x = 0; x < foundINT; x++)
            {
                arrayFileLongTariffID += arrayFileString[x];
                filenameTariffID += arrayFileString[x];
            }
            arrayFileLongTariffID += "</TariffID>";
    
            //Builds arrayFileLongTariffServiceCode from arrayFile to compare to longTariffServiceCode
            y = foundINT + 1;
            arrayFileLongTariffServiceCode = "<TariffServiceCode>";
            while( (arrayFileString[y] != '\n') && (arrayFileString[y] != '\r') && (arrayFileString[y] != '\0') )
            {
                arrayFileLongTariffServiceCode += arrayFileString[y];
                y++;
            }
            arrayFileLongTariffServiceCode += "</TariffServiceCode>";
    
            writeOutputFile(lastFilenameTariffID, filename, filenameTariffID, arrayFileLongTariffID, arrayFileLongTariffServiceCode, lengthLongTariffID, lengthLongTariffServiceCode);
    
            filenameTariffID = "";
        }
    
        inFile.close();
        arrayFile.close();
    
        return 0;
    }
    
    void writeOutputFile(string &lastFilenameTariffID, string filename, string filenameTariffID, string arrayFileLongTariffID, string arrayFileLongTariffServiceCode, int lengthLongTariffID, int lengthLongTariffServiceCode)
    {
        string outputFilename;
        string inFileString;
        size_t found2;
        size_t found3;
        int INTfound2;
        int INTfound3;
    
        //int position;
    
        if( (lastFilenameTariffID != filenameTariffID) && (filenameTariffID != "") ) //Make sure the TariffID is not duplicated, or empty because of eof
        {
            outputFilename = filenameTariffID + "_" + filename;
    
            outFile.open( outputFilename.c_str(), ios::trunc );
    
            /*
            if(outFile.is_open())
            {
                cout << "\n" << outputFilename << "\n";
            }
    
            position = outFile.tellp();
    
            cout << "\n" << position << "\n";
            */
    
            while( getline(inFile, inFileString) )
            {
                found2 = inFileString.find(longTariffID);
                found3 = inFileString.find(longTariffServiceCode);
    
                if( found2 != string::npos )  //If longTariffID is in this line from inFile
                {
                    INTfound2 = int(found2);
    
                    inFileString.erase(INTfound2, lengthLongTariffID);
    
                    inFileString.insert(INTfound2, arrayFileLongTariffID);
    
                    outFile << "\n\nTESTING\n\n";
                    outFile << inFileString << '\n';
                }
                else if( found3 != string::npos )  //If longTariffServiceCode is in this line from inFile
                {
                    INTfound3 = int(found3);
    
                    inFileString.erase(INTfound3, lengthLongTariffServiceCode);
    
                    inFileString.insert(INTfound3, arrayFileLongTariffServiceCode);
    
                    outFile << "\n\nTESTING\n\n";
                    outFile << inFileString << '\n';
                }
                else
                {
                    outFile << "\n\nTESTING\n\n";
                    outFile << inFileString << '\n';
                }
            }//END while( getline(inFile, inFileString) )
            //outFile.flush();
            outFile.close();
            outFile.clear();
        }//END if( (lastFilenameTariffID != filenameTariffID) && (filenameTariffID != "") )
    
        lastFilenameTariffID = filenameTariffID;
        inFile.seekg(0, ios::beg);
    }
    Since I was unable to attach any files to the post, small.txt is below. Keep in mind, this is just an example for testing, not actual code.

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <CISDocument>
        <TariffEntity>
            <TariffService>
                <TariffID>33207</TariffID>
                <TariffServiceCode>TL</TariffServiceCode>
                <Service>Load</Service>
                <TariffCharge>
                    <TariffID>33207</TariffID>
                    <TariffServiceCode>TL</TariffServiceCode>
                    <Charge>*ALL</Charge>
                </TariffCharge>
            </TariffService>
        </TariffEntity>
    </CISDocument>
    Some of the posts/sites I've found suggested using ofstream.clear() or .flush() to reset the flags that may have been thrown in a previous use of the variable, but this hasn't helped.

    Any guidance or suggestions would be appreciated. Thanks in advance.

    ~D

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    The problem is that the input file is opened in main() and then writeOutputFile() loops until it reaches the end of the input file (and produces output in response). On the second and subsequent calls, reading of the input file starts at the end so, after creating the output file, no output is written. Try rewinding the input file before every call of writeOutputFile() (or, alternatively, close it and reopen it, which will mean that reading will start at the beginning of the file).

    I suggest avoiding using globals. By doing so, you obfuscated your code ..... that is almost why you thought the problem was with handling of output files, when the real problem is with handling of the input file.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  3. #3
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    This is one of the worst cases of "variable insanity" that I've ever seen (for such a small program).
    7 globals
    main:
    18 locals
    writeOutputFile:
    7 paremeters
    6 locals
    That's a total of 38 variables in a very small program. This massively overcomplicates your code. It's unlikely that you need more than 10.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Agree with oogabooga. Additionally, declaring everything up-front only makes it worse. Declare variables at the last possible position.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    Registered User
    Join Date
    Mar 2012
    Location
    AL, USA
    Posts
    2
    First all, Thanks for the suggestions. I went back and removed all globals, reduced the number of variables, and attempted to clean up the code.

    This resulted in me confirming grumpy's theory that my problems weren't with outFile. I realized that the program was skipping the WHILE loop (below) after the first pass.
    Code:
    while( getline(inFile, inFileString) )
    So long story short, in the end I replaced
    Code:
    inFile.seekg(0, ios::beg);
    with

    Code:
    inFile.close();
    inFile.clear();
    inFile.open("small.txt");
    and things started working.


    I've attached the rest of the code in case anyone wanted to see it.


    Code:
    #include<iostream>
    #include<fstream>
    #include<string>
    
    using namespace std;
    
    int main()
    {
        ifstream inFile;
        ifstream arrayFile;
        ofstream outFile;
    
        int x;
    
        string temp;
    
        string filename;
        string tariffID;
        string tariffSC;
    
        string newTariffID;
        string newTariffSC;
    
        string inFileString;
        string arrayFileString;
    
        string lastArrayFileTariffID = "";
    
        size_t found, found2, found3;
    
        cout << "\nWhat do you want the filename of the output to be?\n";
        cout << "Please use underscores instead of spaces and include the file extension (.txt):  ";
        cin >> filename;
    
        cout << "What is the Tariff ID you want to change?:  ";
        cin >> tariffID;
    
        cout << "What is the Tariff Service Code you want to change? (Capitalization counts):  ";
        cin >> tariffSC;
    
        inFile.open("small.txt");
        arrayFile.open("array.txt");
    
        while( getline(arrayFile, arrayFileString) )
        {
            found = arrayFileString.find(",");
    
            newTariffID = "";
            newTariffSC = "";
    
            for (x = 0; x < int(found); x++)
            {
                newTariffID += arrayFileString[x];
            }
    
            x = int(found) + 1;
            while ( (arrayFileString[x] != '\r') && (arrayFileString[x] != '\n') && (arrayFileString[x] != '\0') )
            {
                newTariffSC += arrayFileString[x];
                x++;
            }
    
            if( (lastArrayFileTariffID != newTariffID) && (newTariffID != "") )
            {
                temp = newTariffID + "_" + filename;
                outFile.open( temp.c_str(), ios::trunc );
    
                //inFile.seekg(0, ios::beg);
                inFile.close();
                inFile.clear();
                inFile.open("small.txt");
    
                while( getline(inFile, inFileString) )
                {
                    temp = "<TariffID>" + tariffID + "</TariffID>";
                    found2 = inFileString.find(temp);
                    temp = "<TariffServiceCode>" + tariffSC + "</TariffServiceCode>";
                    found3 = inFileString.find(temp);
    
                    if( int(found2) != -1 )
                    {
                        //Length of "<TariffID>" = 10 and Length of "</TariffID>" = 11
                        inFileString.erase(int(found2), (10 + tariffID.length() + 11) );
                        inFileString.insert(int(found2), ("<TariffID>" + newTariffID + "</TariffID>") );
    
                        outFile << inFileString << '\n';
                    }
                    else if( int(found3) != -1 )
                    {
                        //Length of "<TariffServiceCode>" = 19 and Length of "</TariffServiceCode>" = 20
                        inFileString.erase(int(found3), (19 + tariffSC.length() + 20) );
                        inFileString.insert(int(found3), ("<TariffServiceCode>" + newTariffSC + "</TariffServiceCode>") );
    
                        outFile << inFileString << '\n';
                    }
                    else
                    {
                        outFile << inFileString << '\n';
                    }
                }//while( getline(inFile, inFileString) )
    
                outFile.close();
                outFile.clear();
    
            }//if( (lastArrayFileTariffID != newTariffID) && (newTariffID != "") )
    
            lastArrayFileTariffID = newTariffID;
            newTariffID = "";
        }
    
        inFile.close();
        arrayFile.close();
    
        return 0;
    }

    As a side question, could anyone explain why moving the ifstream pointer back to the beginning of the file didn't work?

    Also, CornedBee, could you elaborate on what you meant by "declaring everything up-front only makes it worse. Declare variables at the last possible position." Do you mean that I should declare variables further down in the code? I remember having issues in C if I declared variables after I had code that executed anything.

    Thanks,

    ~D

  6. #6
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    As a side question, could anyone explain why moving the ifstream pointer back to the beginning of the file didn't work?
    Because you probably had a stream error, possibly eof(). Once you get a stream error no further processing will take place on that stream until you clear the error. You could probably have cleared the error then reset the file pointer and been able to read your file correctly. Also note that if you would have just closed the file and reopened it without the clear() you would still have had problems.

    Jim

  7. #7
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Destro09 View Post
    This resulted in me confirming grumpy's theory that my problems weren't with outFile.
    It wasn't a theory. I did a small analysis of your code that went well past the initial steps of hypothesising or theorising about what the cause of your problem might be.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  8. #8
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    I remember having issues in C if I declared variables after I had code that executed anything.
    That's because C89 doesn't allow that. (Newer C versions, like C99, do.) C++ does, and it's highly encouraged to only declare variables once you need them. I'll show you:

    Code:
    #include<iostream>
    #include<fstream>
    #include<string>
     
    using namespace std;
     
    int main()
    {
        cout << "\nWhat do you want the filename of the output to be?\n";
        cout << "Please use underscores instead of spaces and include the file extension (.txt):  ";
        string filename;
        cin >> filename;
     
        cout << "What is the Tariff ID you want to change?:  ";
        string tariffID;
        cin >> tariffID;
     
        cout << "What is the Tariff Service Code you want to change? (Capitalization counts):  ";
        string tariffSC;
        cin >> tariffSC;
     
        ifstream inFile("small.txt");
        ifstream arrayFile("array.txt");
     
        string lastArrayFileTariffID;
        string arrayFileString;
        while( getline(arrayFile, arrayFileString) )
        {
            size_t found = arrayFileString.find(",");
     
            string newTariffID = arrayFileString.substr(0, found);
            // Note: getline() removes trailing newlines, a text mode stream converts \r\n to \n on Windows,
            // and the test arrayFileString[x] != '\0' was too late - by that time, you already had undefined behavior.
            string newTariffSC = arrayFileString.substr(found+1);
     
            if( (lastArrayFileTariffID != newTariffID) && (newTariffID != "") )
            {
                string temp = newTariffID + "_" + filename;
                ofstream outFile( temp.c_str(), ios::trunc );
     
                inFile.seekg(0, ios::beg);
                inFile.clear();
    
                string inFileString;
                while( getline(inFile, inFileString) )
                {
                    temp = "<TariffID>" + tariffID + "</TariffID>";
                    size_t found2 = inFileString.find(temp);
                    temp = "<TariffServiceCode>" + tariffSC + "</TariffServiceCode>";
                    size_t found3 = inFileString.find(temp);
     
                    if( found2 != string::npos )
                    {
                        //Length of "<TariffID>" = 10 and Length of "</TariffID>" = 11
                        inFileString.erase(found2, (10 + tariffID.length() + 11) );
                        inFileString.insert(found2, ("<TariffID>" + newTariffID + "</TariffID>") );
                    }
                    else if( found3 != string::npos )
                    {
                        //Length of "<TariffServiceCode>" = 19 and Length of "</TariffServiceCode>" = 20
                        inFileString.erase(found3, (19 + tariffSC.length() + 20) );
                        inFileString.insert(found3, ("<TariffServiceCode>" + newTariffSC + "</TariffServiceCode>") );
                    }
                    outFile << inFileString << '\n';
                }//while( getline(inFile, inFileString) )
     
            }//if( (lastArrayFileTariffID != newTariffID) && (newTariffID != "") )
     
            lastArrayFileTariffID = newTariffID;
        }
     
        return 0;
    }
    Some resets before loop restarts went away now, for example. I also removed some other cleanups (for example, closing files that are about to go out of scope), and did some other cleanups. Note in particular that none of your casts of the result of find() to int are necessary or a good idea by any means.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Multiple files output
    By onako in forum C++ Programming
    Replies: 1
    Last Post: 04-25-2010, 08:07 AM
  2. To sort an input file and write it as multiple files
    By kavithanarayan in forum C++ Programming
    Replies: 6
    Last Post: 03-16-2010, 12:35 AM
  3. Replies: 5
    Last Post: 02-25-2008, 06:35 AM
  4. File output problem using ofstream
    By yatta!¿ in forum C++ Programming
    Replies: 1
    Last Post: 12-23-2002, 05:05 AM
  5. Removing *Unchanged* Output File (ofstream) :: C++
    By kuphryn in forum C++ Programming
    Replies: 2
    Last Post: 01-05-2002, 07:47 PM

Tags for this Thread