Search code examples
c++csvifstreamofstream

Appending data to csv file, before last entry instead of after last entry. C++


Not easy to formulate that question, so I am sorry for any grief there.. I am writing to a csv file like this at the moment:

double indicators::SMACurrentWrite() {

if ( !boost::filesystem::exists( "./CalculatedOutput/SMAcurrent.csv" ) ) // std::cout << "Can't find my file!" << std::endl;
    {
        std::ofstream SMAfile;              
        SMAfile.open("./CalculatedOutput/SMAcurrent.csv");
        SMAfile << "SMA" << endl << SMA[0] << endl; // .. or with '\n' at the end.
        SMAfile.close();
    }
else    {   
        std::ofstream SMAfile;
        SMAfile.open ("./CalculatedOutput/SMAcurrent.csv", ios::app); // Append mode
    SMAfile << SMA[0] << endl; // Writing data to file
SMAfile.close();
}
return 0;
}

Each time the application runs, a new value is appended to the output file at the end:

SMA
32.325

I guess there is no way of just squeezing that new vector entry in there under the header( and over the number), but that is what I want to accomplish anyway. So I guess I would have to read the existing output file back in,put it in a vector, and then replace the old file ? I started with smth like this:

double indicators::SMACurrentWrite() {

if ( !boost::filesystem::exists( "./CalculatedOutput/SMAcurrent.csv" ) ) // std::cout << "Can't find my file!" << std::endl;
    {
        std::ofstream SMAfile;              
        SMAfile.open("./CalculatedOutput/SMAcurrent.csv", ios::app);
        SMAfile << "SMA" << endl << SMA[0] << endl; // .. or with '\n' at the end.
        SMAfile.close();
    }
else    {   
        std::ofstream SMARfile("./CalculatedOutput/SMAReplacecurrent.csv");
        std::ifstream SMAfile("./CalculatedOutput/SMAcurrent.csv");

            SMARfile << SMA[0] << endl; // Writing data to file
        SMARfile << SMAfile.rdbuf();

        SMAfile.close();
        SMARfile.close();
        std::remove("./CalculatedOutput/SMAcurrent.csv");
            std::rename("./CalculatedOutput/SMAReplacecurrent.csv","./CalculatedOutput/SMAcurrent.csv");
}
return 0;
}

...., but of course that just puts the new data in above the header like this :

32.247
SMA
32.325

..rather than this

SMA
32.247
32.325

I would rather this didn't become such a time- consuming exercise, but I appreciate any help on how I could get this done.


Solution

  • If you read in the first line from the input file you can use that to start the new file and it will leave the file pointer at the second line where the old data starts. Then you can write the new stuff like this:

    if(!boost::filesystem::exists("./CalculatedOutput/SMAcurrent.csv"))
    {
        std::ofstream SMAfile;
        SMAfile.open("./CalculatedOutput/SMAcurrent.csv", ios::app);
        SMAfile << "SMA" << '\n' << SMA[0] << '\n';
        SMAfile.close();
    }
    else
    {
        std::ofstream SMARfile("./CalculatedOutput/SMAReplacecurrent.csv");
        std::ifstream SMAfile("./CalculatedOutput/SMAcurrent.csv");
    
        // first read header from input file
    
        std::string header;
        std::getline(SMAfile, header);
    
        // Next write out the header followed by the new data
        // then everything else
    
        SMARfile << header << '\n';  // Writing header
        SMARfile << SMA[0] << '\n';  // Write new data after header
        SMARfile << SMAfile.rdbuf(); // Write rest of data
    
        SMAfile.close();
        SMARfile.close();
        std::remove("./CalculatedOutput/SMAcurrent.csv");
        std::rename("./CalculatedOutput/SMAReplacecurrent.csv",
            "./CalculatedOutput/SMAcurrent.csv");
    }