Writing .csv files from C++ - c++

I'm trying to output some data to a .csv file and it is outputting it to the file but it isn't separating the data into different columns and seems to be outputting the data incorrectly.
ofstream Morison_File ("linear_wave_loading.csv"); //Opening file to print info to
Morison_File << "Time Force(N/m)" << endl; //Headings for file
for (t = 0; t <= 20; t++) {
u = sin(omega * t);
du = cos(omega * t);
F = (0.5 * rho * C_d * D * u * fabs(u)) + rho * Area * C_m * du;
cout << "t = " << t << "\t\tF = " << F << endl;
Morison_File << t; //Printing to file
Morison_File << F;
}
Morison_File.close();
Time and Force(N/m) are in columns A and B respectively but the t and F values are both printing the first row.
What is the syntax to separate them to print t into column A and F into column B?

There is nothing special about a CSV file. You can create them using a text editor by simply following the basic rules. The RFC 4180 (tools.ietf.org/html/rfc4180) accepted separator is the comma ',' not the semi-colon ';'. Programs like MS Excel expect a comma as a separator.
There are some programs that treat the comma as a decimal and the semi-colon as a separator, but these are technically outside of the "accepted" standard for CSV formatted files.
So, when creating a CSV you create your filestream and add your lines like so:
#include <iostream>
#include <fstream>
int main( int argc, char* argv[] )
{
std::ofstream myfile;
myfile.open ("example.csv");
myfile << "This is the first cell in the first column.\n";
myfile << "a,b,c,\n";
myfile << "c,s,v,\n";
myfile << "1,2,3.456\n";
myfile << "semi;colon";
myfile.close();
return 0;
}
This will result in a CSV file that looks like this when opened in MS Excel:

Here is a STL-like class
File "csvfile.h"
#pragma once
#include <iostream>
#include <fstream>
class csvfile;
inline static csvfile& endrow(csvfile& file);
inline static csvfile& flush(csvfile& file);
class csvfile
{
std::ofstream fs_;
const std::string separator_;
public:
csvfile(const std::string filename, const std::string separator = ";")
: fs_()
, separator_(separator)
{
fs_.exceptions(std::ios::failbit | std::ios::badbit);
fs_.open(filename);
}
~csvfile()
{
flush();
fs_.close();
}
void flush()
{
fs_.flush();
}
void endrow()
{
fs_ << std::endl;
}
csvfile& operator << ( csvfile& (* val)(csvfile&))
{
return val(*this);
}
csvfile& operator << (const char * val)
{
fs_ << '"' << val << '"' << separator_;
return *this;
}
csvfile& operator << (const std::string & val)
{
fs_ << '"' << val << '"' << separator_;
return *this;
}
template<typename T>
csvfile& operator << (const T& val)
{
fs_ << val << separator_;
return *this;
}
};
inline static csvfile& endrow(csvfile& file)
{
file.endrow();
return file;
}
inline static csvfile& flush(csvfile& file)
{
file.flush();
return file;
}
File "main.cpp"
#include "csvfile.h"
int main()
{
try
{
csvfile csv("MyTable.csv"); // throws exceptions!
// Header
csv << "X" << "VALUE" << endrow;
// Data
csv << 1 << "String value" << endrow;
csv << 2 << 123 << endrow;
csv << 3 << 1.f << endrow;
csv << 4 << 1.2 << endrow;
}
catch (const std::exception& ex)
{
std::cout << "Exception was thrown: " << e.what() << std::endl;
}
return 0;
}
Latest version here

Change
Morison_File << t; //Printing to file
Morison_File << F;
To
Morison_File << t << ";" << F << endl; //Printing to file
a , would also do instead of ;

You must ";" separator, CSV => Comma Separator Value
ofstream Morison_File ("linear_wave_loading.csv"); //Opening file to print info to
Morison_File << "'Time'; 'Force(N/m)' " << endl; //Headings for file
for (t = 0; t <= 20; t++) {
u = sin(omega * t);
du = cos(omega * t);
F = (0.5 * rho * C_d * D * u * fabs(u)) + rho * Area * C_m * du;
cout << "t = " << t << "\t\tF = " << F << endl;
Morison_File << t << ";" << F;
}
Morison_File.close();

If you wirte to a .csv file in C++ - you should use the syntax of :
myfile <<" %s; %s; %d", string1, string2, double1 <<endl;
This will write the three variables (string 1&2 and double1) into separate columns and leave an empty row below them. In excel the ; means the new row, so if you want to just take a new row - you can alos write a simple ";" before writing your new data into the file. If you don't want to have an empty row below - you should delete the endl and use the:
myfile.open("result.csv", std::ios::out | std::ios::app);
syntax when opening the .csv file (example the result.csv). In this way next time you write something into your result.csv file - it will write it into a new row directly below the last one - so you can easily manage a for cycle if you would like to.

As explained above by #kris, depending on the region configurations of MS Excel it won't interpret the comma as the separator character. In my case I had to change it to semi-colon

Related

fstream stops to read at substitute control character

I'm writing a simple encryption program in C++ to encrypt a text-based file.
It's using a simple XOR cipher algorithm, but this produces ASCII control characters in the output file. When I try to read from the newly encrypted file with std::ifstream, it stumbles upon character #26, it stops and becomes unable to read the rest of the file.
Example if I try to encrypt this text:
This is just a simple sample
text with two rows and one sentence.
It turns it to this
/[[[[[
[[[ [[[U
When I try to read that file in my program, it can't read past the character at position 15, so I get a half encrypted file.
How can I fix this?
Here's the code:
#include <iostream>
#include <Windows.h>
#include <string>
#include <fstream>
void Encrypt(char encryptionKey, std::string filename)
{
std::ifstream sourceFile(filename);
std::ofstream outputFile(filename.substr(0, filename.find_last_of("\\")) + "\\Encrypted" + filename.substr(filename.find_last_of("\\") + 1), std::ofstream::out | std::ofstream::trunc);
std::string sourceLine;
std::string outputLine;
long numLines = 0;
if (sourceFile.is_open())
{
std::cout << "Opening file: " + filename + " for encryption" << std::endl;
while (sourceFile.good()) // This iterates over the whole file, once for each line
{
sourceLine = ""; //Clearing the line for each new line
outputLine = ""; //Clearing the line for each new line
std::getline(sourceFile, sourceLine);
for (int i = 0; i < sourceLine.length(); i++) // Looping through all characters in each line
{
char focusByte = sourceLine[i] ^ encryptionKey;
std::cout << " focusByte: " << focusByte << std::endl;
outputLine.push_back(focusByte);
//std::cout << sourceLine << std::flush;
}
numLines++;
outputFile << outputLine << std::endl;
}
}
sourceFile.close();
outputFile.close();
}
void Decrypt(unsigned int encryptionKey, std::string filename)
{
std::ifstream sourceFile(filename);
std::ofstream outputFile(filename.substr(0, filename.find_last_of("\\")) + "\\Decrypted" + filename.substr(filename.find_last_of("\\") + 1), std::ofstream::out | std::ofstream::trunc);
std::string sourceLine;
std::string outputLine;
long numLines = 0;
if (sourceFile.is_open())
{
std::cout << "Opening file: " + filename + " for decryption" << std::endl;
while (sourceFile.good()) // This iterates over the whole file, once for each line
{
if (sourceFile.fail() == true)
std::cout << "eof" << std::endl;
sourceLine = ""; //Clearing the line for each new line
outputLine = ""; //Clearing the line for each new line
std::getline(sourceFile, sourceLine);
for (int i = 0; i < sourceLine.length(); i++) // Looping through all characters in each line
{
char focusByte = sourceLine[i] ^ encryptionKey;
std::cout << " focusByte: " << focusByte << std::endl;
outputLine.push_back(focusByte);
}
numLines++;
outputFile << outputLine << std::endl;
}
}
sourceFile.close();
outputFile.close();
}
int main(int argument_count,
char * argument_list[])
{
system("color a");
std::string filename;
if (argument_count < 2)
{
std::cout << "You didn't supply a filename" << std::endl;
}
else
{
filename = argument_list[1];
std::cout << "Target file: " << filename << std::endl;
std::cout << "Press e to encrypt the selected file, Press d to decrypt the file > " << std::flush;
char choice;
while (true)
{
std::cin >> choice;
if (choice == 'e')
{
Encrypt(123, filename);
break;
}
else if (choice == 'd')
{
Decrypt(123, filename);
break;
}
else
{
std::cout << "please choose option e or d for encryption respectivly decryption" << std::endl;
}
}
}
std::cout << "\nPaused, press Enter to continue > " << std::flush;
system("Pause");
return EXIT_SUCCESS;
}
In Decrypt(), after the first call to std::getline(), sourceFile.good() is false and sourceFile.fail() is true, which is why you stop reading subsequent lines from the encrypted file.
The reason is because the encrypted file has an encoded 0x1A byte in it, and depending on your platform and STL implementation, that character likely gets interpreted as an EOF condition, thus enabling the std::ifstream's eofbit state, terminating further reading.
In my compiler's STL implementation on Windows, when std::ifstream reads from a file, it ultimately calls a function named _Fgetc():
template<> inline bool _Fgetc(char& _Byte, _Filet *_File)
{ // get a char element from a C stream
int _Meta;
if ((_Meta = fgetc(_File)) == EOF) // <-- here
return (false);
else
{ // got one, convert to char
_Byte = (char)_Meta;
return (true);
}
}
When it tries to read an 0x1A character, fgetc() returns EOF, and when _Fgetc() returns false, std::getline() sets the eofbit on the std::ifstream and exits.
Check your compiler's STL for similar behavior.
This behavior is because you are opening the encrypted file in text mode. You need to open the encrypted file in binary mode instead:
std::ifstream sourceFile(..., std::ifstream::binary);
Also, you should enable binary mode on the encrypted file in Encrypt() as well:
std::ofstream outputFile(..., std::ofstream::binary | std::ofstream::trunc);
Try something more like this instead:
#include <Windows.h>
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
void Encrypt(char encryptionKey, const std::string &filename)
{
std::string::size_type pos = filename.find_last_of("\\");
std::string out_filename = filename.substr(0, pos+1) + "Encrypted" + filename.substr(pos + 1);
std::ifstream sourceFile(filename.c_str());
std::ofstream outputFile(out_filename.c_str(), std::ofstream::binary | std::ofstream::trunc);
if (sourceFile.is_open())
{
std::cout << "Opened file: " + filename + " for encryption" << std::endl;
std::string line;
long numLines = 0;
while (std::getline(sourceFile, line)) // This iterates over the whole file, once for each line
{
for (std::string::size_type i = 0; i < line.length(); ++i) // Looping through all characters in each line
{
char focusByte = line[i] ^ encryptionKey;
std::cout << " focusByte: " << focusByte << std::endl;
line[i] = focusByte;
//std::cout << line << std::flush;
}
outputFile << line << std::endl;
++numLines;
}
}
}
void Decrypt(char encryptionKey, const std::string &filename)
{
std::string::size_type pos = filename.find_last_of("\\");
std::string out_filename = filename.substr(0, pos+1) + "Decrypted" + filename.substr(pos + 1);
std::ifstream sourceFile(filename.c_str(), std::ifstream::binary);
std::ofstream outputFile(out_filename.c_str(), std::ofstream::trunc);
if (sourceFile.is_open())
{
std::cout << "Opened file: " + filename + " for decryption" << std::endl;
std::string line;
long numLines = 0;
while (std::getline(sourceFile, line)) // This iterates over the whole file, once for each line
{
for (std::string::size_type i = 0; i < line.length(); ++i) // Looping through all characters in each line
{
char focusByte = line[i] ^ encryptionKey;
std::cout << " focusByte: " << focusByte << std::endl;
line[i] = focusByte;
}
outputFile << line << std::endl;
++numLines;
}
std::cout << "eof" << std::endl;
}
}
int main(int argument_count, char* argument_list[])
{
std::system("color a");
std::string filename;
if (argument_count < 2)
{
std::cout << "Enter a file to process: " << std::flush;
std::getline(std::cin, filename);
}
else
{
filename = argument_list[1];
}
if (filename.empty())
{
std::cout << "You didn't supply a filename" << std::endl;
return EXIT_FAILURE;
}
std::cout << "Target file: " << filename << std::endl;
std::cout << "Press e to encrypt the file" << std::endl;
std::cout << "Press d to decrypt the file" << std::endl;
char choice;
while (true)
{
std::cout << "> " << std::flush;
std::cin >> choice;
if (choice == 'e')
{
Encrypt(123, filename);
break;
}
else if (choice == 'd')
{
Decrypt(123, filename);
break;
}
else
{
std::cout << "please choose option e or d for encryption or decryption, respectively" << std::endl;
}
}
std::cout << std::endl << "Paused, press Enter to continue" << std::flush;
std::system("pause");
return EXIT_SUCCESS;
}
That being said, keep in mind that when using XOR, some of the encrypted characters might end up being \r (0x0D) or \n (0x0A), which will interfere with std::getline() when decrypting the file later on, producing a decrypted output that does not match the original text input.
Since you should be treating the encrypted file as binary, you should not be reading/writing the file as text at all. Choose a different format for your encrypted output that does not rely on line-break semantics in text vs binary mode.
For example:
#include <Windows.h>
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
void Encrypt(char encryptionKey, const std::string &filename)
{
std::string::size_type pos = filename.find_last_of("\\");
std::string out_filename = filename.substr(0, pos+1) + "Encrypted" + filename.substr(pos + 1);
std::ifstream sourceFile(filename.c_str());
std::ofstream outputFile(out_filename.c_str(), std::ofstream::binary | std::ofstream::trunc);
if (sourceFile.is_open())
{
std::cout << "Opened file: " + filename + " for encryption" << std::endl;
std::string line;
std::string::size_type lineLen;
long numLines = 0;
while (std::getline(sourceFile, line)) // This iterates over the whole file, once for each line
{
lineLen = line.length();
for (std::string::size_type i = 0; i < lineLen; ++i) // Looping through all characters in each line
{
char focusByte = line[i] ^ encryptionKey;
std::cout << " focusByte: " << focusByte << std::endl;
line[i] = focusByte;
//std::cout << line << std::flush;
}
outputFile.write((char*)&lineLen, sizeof(lineLen));
outputFile.write(line.c_str(), lineLen);
++numLines;
}
}
}
void Decrypt(char encryptionKey, const std::string &filename)
{
std::string::size_type pos = filename.find_last_of("\\");
std::string out_filename = filename.substr(0, pos+1) + "Decrypted" + filename.substr(pos + 1);
std::ifstream sourceFile(filename.c_str(), std::ifstream::binary);
std::ofstream outputFile(out_filename.c_str(), std::ofstream::trunc);
if (sourceFile.is_open())
{
std::cout << "Opened file: " + filename + " for decryption" << std::endl;
std::string line;
std::string::size_type lineLen;
long numLines = 0;
while (sourceFile.read((char*)&lineLen, sizeof(lineLen))) // This iterates over the whole file, once for each line
{
line.resize(lineLen);
if (!sourceFile.read(&line[0], lineLen))
break;
for (std::string::size_type i = 0; i < lineLen; ++i) // Looping through all characters in each line
{
char focusByte = line[i] ^ encryptionKey;
std::cout << " focusByte: " << focusByte << std::endl;
line[i] = focusByte;
}
outputFile << line << std::endl;
++numLines;
}
std::cout << "eof" << std::endl;
}
}
int main(int argument_count, char* argument_list[])
{
std::system("color a");
std::string filename;
if (argument_count < 2)
{
std::cout << "Enter a file to process: " << std::flush;
std::getline(std::cin, filename);
}
else
{
filename = argument_list[1];
}
if (filename.empty())
{
std::cout << "You didn't supply a filename" << std::endl;
return EXIT_FAILURE;
}
std::cout << "Target file: " << filename << std::endl;
std::cout << "Press e to encrypt the file" << std::endl;
std::cout << "Press d to decrypt the file" << std::endl;
char choice;
while (true)
{
std::cout << "> " << std::flush;
std::cin >> choice;
if (choice == 'e')
{
Encrypt(123, filename);
break;
}
else if (choice == 'd')
{
Decrypt(123, filename);
break;
}
else
{
std::cout << "please choose option e or d for encryption or decryption, respectively" << std::endl;
}
}
std::cout << std::endl << "Paused, press Enter to continue" << std::flush;
std::system("pause");
return EXIT_SUCCESS;
}
ASCII value 26 is EOF on some operating systems.
You should probably treat your encrypted file as a byte stream rather than a text file for reading and writing. That means either using read() and write() functions of the IOStream or at the very least opening the files in binary mode.
If you're just enciphering your text instead of encrypting, maybe choose a different cipher (eg. ROT13) that is closed on the set of printable ASCII or UTF-8 characters.
I compiled your code in Linux (minus all the Windows stuff)...
I get this when encrypting your sentence with your code:
/[[[[[
[[[ [[[U
It also decrypts back to the original sentence. Without the goofy characters, it is the same as your output so your actual issue seems related to the encoding of the file and the program you are using to view the results. Stephan is correct in saying you should be reading/writing bytes instead of text. This can cause all sorts of issues with the characters you create. For example, line feeds and carriage returns since you are using getline().
Edit: Strange. After editing this answer, all the odd characters disappeared. Here is a screenshot:

How to open and read a file based on user input c++

I have an assignment that wants me to write a program that reads a text file, then outputs a modified version of that file using a version of Ceasar cipher that shifts the characters of the file that the user calls based on the shift amount that they input. For example if my file reads "hi" and they shift it by 1 it should read "ij". But when I run the program it doesnt recognize when I call in1 or out1 and I just get an error message. Can anyone help me figure out what I'm doing wrong or offer any advice on how to move forward? Thank you in advance!
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cctype>
using namespace std;
int main()
{
//Declare user variables
int shift, file1chars = 0;
char filename[25];
ifstream in1;
ofstream out1;
do
{
in1.clear(); //clear status flags
//Prompt user to enter name of input file and amount of shift
cout << "Please enter the name of the input file." << endl;
cout << "Filename: ";
cin >> filename;
//Open file name
in1.open(filename);
//Error message if no file
if (!in1)
cout << "That is not a valid file. Try again\n";
} while (!in1);
do
{
out1.clear(); //clear status flags
//prompt user to input out file
cout << "Please enter the name of the output file." << endl;
cout << "Filename: ";
cin >> filename;
out1.open(filename);
//Error message if no file
if (!out1)
cout << "That is not a valid file. Try again\n";
} while (!out1);
//write some code to the input file
in1 >> "hi"
//write the integers in a different order to the output file
out1 << //idk where to go from here to initiate shift
//prompt user to enter shift
cout << "Please intput the shift amount: ";
cin >> shift;
cout << "Processing complete" << endl;
//Call file (?)
//Tell user file input is complete and is now printing statistics
cout << "\nShifted input file Complete. Now printing statistics " << endl;
//Show statistics for file
cout << "\nStatistics for file: " << filename << endl;
cout << "------------------------------------------------";
//Show characters in file and stats before shift
cout << "\n\nTotal # of characters in file: " << file1chars << endl;
cout << "Statistics before shift: " << endl;
//Show file before shift
//Show user stats after shift
cout << "\nStatistics after shift: " << endl;
//File after shift
//Close files
out1.close();
in1.close();
return 0;
}
Instead of looking at your code for line by line to see where the problem(s) could be, I ask you to think about your requirements and write code that expresses the intent as closely as possible. Create functions that follow the intended functionality.
Get the input file name.
Get the output file name.
Read the contents of the input file.
Transform the contents of the input file to create the output string.
Write the output string to the output file.
In pseudo code,
int main()
{
infile = get_input_filename()
outfile = get_output_filename()
contents = get_file_contents(infile)
output = transform_input(contents)
write_output(outfile, output)
}
Convert that to C++ code:
// Declare the functions.
std::string get_input_filename();
std::string get_output_filename();
std::string get_file_contents(std::string const& infile)
std::string transform_input(std::string const& contents)j
void write_output(std::string const& outfile, std::string const& output);
// Use them in main.
int main()
{
std::string infile = get_input_filename();
std::string outfile = get_output_filename();
std::string contents = get_file_contents(infile);
std::string output = transform_input(contents);
write_output(outfile, output);
}
// Implement the functions.
std::string get_input_filename()
{
std::string filename;
cout << "Please enter the name of the input file." << endl;
cout << "Filename: ";
cin >> filename;
return filename;
}
std::string get_output_filename()
{
std::string filename;
cout << "Please enter the name of the output file." << endl;
cout << "Filename: ";
cin >> filename;
return filename;
}
std::string get_file_contents(std::string const& infile)
{
std::ifstream inf(infile);
std::string contents;
int c;
while ( (c = inf.get()) != EOF )
{
contents += c;
}
return contents;
}
std::string transform_input(std::string const& contents)
{
std::string res;
// Do the needful to transform contents to res.
return res;
}
void write_output(std::string const& outfile, std::string const& output)
{
std::ofstream outf(outfile);
outf.write(output.c_str(), output.size();
}
If you are able to use a class or struct and functions I would propose something like this:
main.cpp
#include <string>
#include <iostream>
#include <fstream>
#include "CaesarShift.h"
int main() {
std::string filename;
std::cout << "Please enter the name of the input file. ";
std::cin >> filename;
std::ifstream fileIn;
std::string text;
fileIn.open( filename );
if ( !fileIn.is_open() ) {
std::cout << "Failed to open file: " << filename << "." << std::endl;
}
fileIn >> text;
fileIn.close();
CaesarText caesarText;
caesarText.addText( text );
std::cout << "Contents of the Caesar Text before peforming a Caesar Shift:\n"
<< caesarText << std::endl;
int amount = 0;
std::cout << "Please enter the amount to shift the text ";
std::cin >> amount;
std::cout << "Now performing the Caesar Shift: " << std::endl;
caesarShift( caesarText, amount );
std::cout << "Caesar Text after performing a Caesar Shift:\n"
<< ceasarText << std::endl;
std::ofstream fileOut;
fileOut.open( std::string( "shifted_" + filename ) );
if ( !fileOut.is_open() ) {
std::cout << "Failed to open shifted_" << filename << std::endl;
}
// Uncomment to print original text to file otherwise only modified text will be printed.
// fileOut << caesarText.originalText() << std::endl;
fileOut << caesarText.shiftedText() << std::endl;
fileOut.close();
system( "PAUSE" );
return 0;
}
CaesarShift.h
#ifndef CAESAR_SHIFT_H
#define CAESAR_SHIFT_H
class CaesarText {
std::string _originalText;
std::string _shiftedText;
public:
caesarText() = default;
explicit CeasarText( const std::string& text ) :
_originalText( text ) {}
void addText( const std::string& text ) {
_originalText = text;
}
std::string originalText() const {
return _originalText;
}
std::string shiftedText() const {
return _shiftedText;
}
friend void caesarShift( caesarText& c, int amount );
friend std::ostream& operator<<( std::ostream& out, const caesarText& ceasarText );
};
#endif // !CAESAR_SHIFT_H
CaesarShift.cpp
#include "CaesarShift.h"
#include <string>
#include <iostream>
#include <algorithm>
// Overloaded ostream operator
std::ostream& operator<<( std::ostream& o, const CaesarText& c ) {
o << "Original Text: " << c._originalText << "\n";
o << "Shifted Text: " << c._shiftedText << "\n";
return o;
}
// public friend function (visible in main) not actually a part of the class
// but performs operations on it.
// To perform the Caesar Shift here are 3 possible variations of implementing the same task.
void caesarShift( Caesar Text& text, int amount ) {
// Bound amount to the number of characters in the alphabet
// the same value used in any of the three variations below.
amount %= 26;
// Older c++ style loop.
/*for ( std::size_t i = 0; i < text._originalText.length(); i++ ) {
char c = text._originalText[i] + amount;
text._shiftedText += c;
}*/
// Modern C++ style loop
/*for ( auto& c : text._originalText ) {
text._shiftedText += c + amount;
}*/
// std::transform( s1.begin, s1.end, back_inserter( s2 ), lamda as predicate );
/*std::transform( text._originalText.begin(), text._originalText.end(),
std::back_inserter( text._shiftedText ),
[amount]( unsigned char c ) -> unsigned char { return c + amount; }
);*/
}
As for the 3 different variations of performing the Caesar Shift you can just uncomment the appropriate block section.

C++ ofstream only outputting last line of data from ifstream

I am trying to read from a file and output data to a separate file. Only problem is that when I run the program the output on the file is from the data on the last line of the input file. I also don't want to append the output file since I don't want the data to duplicate when I rerun the program which is why i'm not using ios::app in the output.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//class declaration
class call_record{
public:
string cell_number;
int relays;
int call_length;
double net_cost;
double tax_rate;
double call_tax;
double total_cost;
};
//Prototypes
void input(ifstream & in, call_record &);
void process(call_record &);
void output(call_record &);
//Input function
void input(ifstream & in, call_record & customer_record){
in >> customer_record.cell_number >> customer_record.relays >>
customer_record.call_length;
}
//Process function
void process(call_record & customer_record){
if(customer_record.relays >= 0 && customer_record.relays <=5){
customer_record.tax_rate = 0.01;
} else if(customer_record.relays >= 6 && customer_record.relays <=11){
customer_record.tax_rate = 0.03;
} else if(customer_record.relays >= 12 && customer_record.relays <=20){
customer_record.tax_rate = 0.05;
} else if(customer_record.relays >= 21 && customer_record.relays <=50){
customer_record.tax_rate = 0.12;
}
//net cost of call
customer_record.net_cost = (customer_record.relays/50 * 0.40 *
customer_record.call_length);
//cost of tax on call
customer_record.call_tax = customer_record.net_cost *
customer_record.tax_rate;
//Total cost of call
customer_record.total_cost = customer_record.net_cost +
customer_record.call_tax;
}
void output(call_record & customer_record){
ofstream out("weekly_call_info.txt");
out.setf(ios::showpoint);
out.precision(2);
out.setf(ios::fixed);
out << customer_record.cell_number << " " << customer_record.relays << " "
<< customer_record.call_length << " " << customer_record.net_cost << " "
<< customer_record.tax_rate << " " << customer_record.call_tax << " " <<
customer_record.total_cost << endl;
out.close();
}
int main(){
call_record customer_record;
ifstream in("call_data.txt");
if(in.fail()){
cout << "Your input file does not exist or did not open properly." <<
endl;
} else {
while (!in.eof()){
input(in, customer_record);
process(customer_record);
output(customer_record);
}
}
in.close();
return 0;
}
This is different than the other posts because I am using both an input stream and an output stream in 2 separate functions and I don't think I fully understand how to implement them correctly in my main function.
The problem is that you are always creating weekly_call_info.txt each time output() is called and truncating the existing file. This is because you are not specifying the std::ios_base::app ("append") open mode flag, so the existing content of weekly_call_info.txt is lost. See this page for a helpful table that shows the equivalent C-style mode strings for the different combinations of open mode flags: http://en.cppreference.com/w/cpp/io/basic_filebuf/open
I suggest passing a reference to the std::ostream to which you want to output data to the output() function:
void output(call_record & customer_record, std::ostream& out){
out << customer_record.cell_number << " " << customer_record.relays << " "
<< customer_record.call_length << " " << customer_record.net_cost << " "
<< customer_record.tax_rate << " " << customer_record.call_tax << " " <<
customer_record.total_cost << endl;
}
int main(){
call_record customer_record;
ifstream in("call_data.txt");
if(in.fail()){
cout << "Your input file does not exist or did not open properly." << endl;
} else {
ofstream out("weekly_call_info.txt");
out.setf(ios::showpoint);
out.precision(2);
out.setf(ios::fixed);
for (;;) {
input(in, customer_record);
if (!in) break;
process(customer_record);
output(customer_record, out);
}
}
return 0;
}
If you really do want to open weekly_call_info.txt for writing multiple times, you will want to use the std::ios_base::app open mode flag to append to the existing file. See appending to a file with ofstream.

Data doesn't load into c++ vector correctly

I am trying to load a text file and import the contents into a vector of structs.
Here are my definitions
typedef struct
{
string pcName, pcUsername, pcPassword, pcMessage, pcAdvertisement; //I know that
//this is incorrect convention. It was originally a char*
}
ENTRY;
vector<ENTRY> entries;
fstream data;
Here is my display data function
void DisplayData()
{
std::cout << (int)(entries.size() / 5) <<" entries" << endl;
for(int i = 1; i <=(int)entries.size()/5; i++)
{
cout << endl << "Entry " << i << ":" << endl
<< "Name: " << entries[i].pcName << endl
<< "Username: " << entries[i].pcUsername << endl
<< "Password: " << entries[i].pcPassword << endl
<< "Message: " << entries[i].pcMessage << endl
<< "Advertisement: " << entries[i].pcAdvertisement << endl;
}
}
and here is my Load Data function
bool LoadData(const char* filepath)
{
std::string lineData ;
int linenumber = 1 ;
data.open(filepath, ios::in);
ENTRY entry_temp;
if(!data.is_open())
{
cerr << "Error loading file" << endl;
return false;
}
while(getline(data, lineData))
{
if(linenumber==1) {entry_temp.pcName = lineData;}
else if(linenumber==2) {entry_temp.pcUsername = lineData;}
else if(linenumber==3) {entry_temp.pcPassword = lineData;}
else if(linenumber==4) {entry_temp.pcMessage = lineData;}
else if(linenumber==5) {entry_temp.pcAdvertisement = lineData;}
entries.push_back(entry_temp);
if(linenumber == 5)
{
linenumber = 0;
}
linenumber++;
}
data.close();
puts("Database Loaded");
return true;
}
Here is the text file I am loading:
Name1
Username1
Password1
Message1
Ad1
And here is the result of the display data function after calling load data:
1 entries
Entry 1:
Name: Name1
Username Username1
Password:
Message:
Advertisement:
As you can see, the first two load but the last three don't. When I did this with an array instead of a vector, it worked fine so I don't know what I'm doing wrong. Thanks.
I suggest that you read each line directly into the data field where it goes:
getline(data, entry_temp.pcName);
getline(data, entry_temp.pcUsername);
getline(data, entry_temp.pcPassword);
getline(data, entry_temp.pcMessage);
getline(data, entry_temp.pcAdvertisement);
entries.push_back(entry_temp);
This makes your intent much clearer than your current while loop. It also creates a single entry for all 4 input lines rather than one for each input line (with the other three blank). Now you can read several "entries" by using a while loop that checks if you have reached the end of the file.
Doing this will also make printing out the data much easier since the vector will have exactly the number of entries rather than five times as many as you expect (which also eats up a lot more memory than you need to).
Your DisplayData function is a little weird, and so is your LoadData.
Your LoadData pushes back a new copy of the current ENTRIES entry with every line. Your DisplayData starts at 1 (which is not the beginning of any vector or array), and iterates only up to the 1/5th entry of the entire vector.
This needs a heavy rework.
First, the size() member of any standard container returns the number of elements that it contains, and will not take the number of fields in a contained struct into account.
For future reference, you'll want to post your question in a complete, standalone example that we can immediately compile to help. (see http://sscce.org/)
Try this modified data, which runs correctly, and see if you can tell what is being done differently:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
typedef struct
{
string pcName, pcUsername, pcPassword, pcMessage, pcAdvertisement;
}
ENTRY;
vector<ENTRY> entries;
fstream data;
bool LoadData(const char* filepath)
{
std::string lineData ;
int linenumber = 1 ;
data.open(filepath, ios::in);
ENTRY entry_temp;
if(!data.is_open())
{
cerr << "Error loading file" << endl;
return false;
}
while(getline(data, lineData))
{
if(linenumber==1) {entry_temp.pcName = lineData;}
else if(linenumber==2) {entry_temp.pcUsername = lineData;}
else if(linenumber==3) {entry_temp.pcPassword = lineData;}
else if(linenumber==4) {entry_temp.pcMessage = lineData;}
else if(linenumber==5) {entry_temp.pcAdvertisement = lineData;}
if(linenumber == 5)
{
entries.push_back(entry_temp);
linenumber = 0;
}
linenumber++;
}
data.close();
puts("Database Loaded");
return true;
}
void DisplayData()
{
std::cout << entries.size() <<" entries" << endl;
for(int i = 0; i < entries.size(); i++)
{
cout << endl << "Entry " << i << ":" << endl
<< "Name: " << entries[i].pcName << endl
<< "Username: " << entries[i].pcUsername << endl
<< "Password: " << entries[i].pcPassword << endl
<< "Message: " << entries[i].pcMessage << endl
<< "Advertisement: " << entries[i].pcAdvertisement << endl;
}
}
int main()
{
LoadData("/tmp/testdata");
DisplayData();
return (0);
}
While I think #code-guru has the right idea, I'd take the same idea just a little further, and make your code work a little more closely with the standard library. I'd do that by reading a data item with a stream extractor, and displaying it with stream inserter. So, the extractor would look something like this:
std::istream &operator>>(std::istream &is, ENTRY &e) {
getline(is, e.pcName);
getline(is, e.pcUsername);
getline(is, e.pcPassword);
getline(is, e.pcMessage);
getline(is, e.pcAdvertisement);
return is;
}
..and the inserter would look something like this:
std::ostream &operator<<(std::ostream &os, ENTRY const &e) {
os << e.pcName << "\n";
os << e.pcUsername << "\n";
os << e.pcPassword << "\n";
os << e.pcMessage << "\n";
os << e.pcAdvertisement << "\n";
return os;
}
With those in place, loading and displaying the data becomes fairly straightforward.
Load the data:
std::ifstream in("yourfile.txt");
std::vector<ENTRY> data((std::istream_iterator<ENTRY>(in)),
std::istream_iterator<ENTRY>());
Display the data:
for (auto const & e: data)
std::cout << e << "\n";
For the moment, I haven't tried to duplicate the format you were using to display the data -- presumably the modifications for that should be fairly obvious.

ofstream doesn't open, or write to files

I've been looking at this for hours and I just know the answer is simple. It seems no matter what I do I cannot open a file. It's a multi-class program so in the header I have
#include <iostream>
#include < fstream>
class A{
string path;
A(string p): path(p){}
...
...
void PrintToFile();
void PrintBase();
void PrintNext();
...
...
};
and in the cpp file I have
#include "A.h"
void A::PrintToFile(){
ofstream f(path.c_str(), ios::out);
assert(f.is_open);
f << "markuptext" << endl;
PrintBase();
f << "endtag" << endl;
f.close();
}
void A::PrintBase(){
ofstream f(path.c_str(), ios::app);
assert(f.is_open);
f << "markuptext" << endl;
f << somevale << endl;
PrintNext();
f << "endtag" << endl;
f.close()
}
void A::PrintNext(){
ofstream f (path.c_str(), ios::app);
assert(f.is_open);
f << "markuptext" << endl;
f << somevalue << endl;
f << "endtag" << endl;
f.close()
}
I've played around with the flags on the constructors and with the open commands as well. And once it managed to open a file, but it never wrote anything to the file. If you have any insights I'd much appreciate it.
edit
Thanks for all the help guys, looks like I was trying to open a file with "". But even now after I've got that straightened out, my code is not writing to that open file. I checked my permissions and I'm doing chmod a+rwx... well here's the code in more detail.
#ifndef XML_WRITER_H
#define XML_WRITER_H
#include "WordIndex.h"
#include "PageIndex.h"
#include "StringUtil.h"
#include "CS240Exception.h"
#include <iostream>
#include <fstream>
/* prints out the wordIndex to an xml file
*/
class XMLWriter{
private:
WordIndex * wIndex;
PageIndex * pIndex;
URL baseurl;
//const char * file;
ofstream f;
public:
XMLWriter();
XMLWriter(string base);
XMLWriter(XMLWriter & other){
assert(&other != NULL);
Init(other);
}
XMLWriter & operator =(XMLWriter & other){
Free();
Init(other);
}
~XMLWriter(){
Free();
}
void Load(WordIndex & wi, PageIndex & pi);
//prints to the file
void Print(char * ofile);
private:
void Init(XMLWriter & other){
baseurl = other.baseurl;
wIndex = other.wIndex;
pIndex = other.pIndex;
}
void Free(){
}
void PrintWebsite();
void PrintStartURL();
void PrintPages();
void PrintIndex();
void PrintWord(OccurenceSet ocs);
void PrintValue(string s);
void PrintOccurence(Occurence o);
void PrintPage(Page & page );
void PrintDescription(string dscrptn );
void PrintValue(int n );
void PrintURL(URL url );
};
#endif
.cpp file
#include "XMLWriter.h"
XMLWriter::XMLWriter(){
}
XMLWriter::XMLWriter( string base): baseurl(base){
//cout << "filename : " << filename << endl;
//file = filename.c_str();
//cout << "file : " << *file << endl;
}
void XMLWriter::Load(WordIndex & wi, PageIndex & pi){
wIndex = &wi;
pIndex = π
wIndex->ResetIterator();
pIndex->ResetIterator();
}
void XMLWriter::Print(char * filename){
cout << filename << endl;
ofstream f(filename);
if(!f){
cout << "file : " << filename;
throw CS240Exception("could not open the file for writing");
}
PrintWebsite();
f.close();
}
//private methods
//
void XMLWriter::PrintWebsite(){
f <<"<website>\n";
PrintStartURL();
PrintPages();
PrintIndex();
f << "</website>" << endl;
}
// startURL
//
void XMLWriter::PrintStartURL( ){
f << "\t" << "<start-url>"<< endl;
string val = baseurl.Value();
StringUtil::EncodeToXml(val);
f << "\t\t" << val << endl;
f << "\t" << "</start-url>"<< endl;
}
//pages
//
void XMLWriter::PrintPages(){
f << "\t" << "<pages>"<< "\n";
while(pIndex->HasNext())
PrintPage(*(pIndex->Next()));
f << "\t" <<"</pages>"<< '\n';
}
void XMLWriter::PrintPage(Page & page ){
f << "\t\t" <<"<page>"<< endl;
PrintURL(page.Value());
PrintDescription(page.Description() );
f << "\t\t" <<"</page>"<< endl;
}
void XMLWriter::PrintURL(URL url){
f << "\t\t\t<url>"<< endl;
f << "\t\t\t\t" << StringUtil::EncodeToXmlCopy(url.Value()) << endl;
f << "\t\t\t</url>"<< endl;
}
void XMLWriter::PrintDescription(string dscrptn){
f << "\t\t\t<description>";
f << StringUtil::EncodeToXmlCopy(dscrptn);
f << "</description>"<< endl;
}
//index
//
void XMLWriter::PrintIndex(){
f << "\t<index>"<< endl;
while(wIndex->HasNext())
PrintWord(*(wIndex->Next()) );
f << "\t</index>"<< endl;
}
void XMLWriter::PrintWord(OccurenceSet ocs ){
f << "\t\t<word>" << endl;
PrintValue(ocs.Value());
ocs.ResetIterator();
while(ocs.HasNext())
PrintOccurence(*(ocs.Next()) );
f << "\t\t</word>"<< endl;
}
void XMLWriter::PrintValue(string s ){
f << "\t\t\t<value>";
f << StringUtil::EncodeToXmlCopy(s);
f << "</value>"<< endl;
}
void XMLWriter::PrintOccurence(Occurence o ){
f << "\t\t\t<occurence>" << endl;
PrintURL(o.Value()->Value());
PrintValue(o.NumOfOccur());
f << "<\t\t\t/occurence>"<< endl;
}
void XMLWriter::PrintValue(int n ){
f << "\t\t\t\t<count>";
f << n;
f << "</count>"<< endl;
}
it won't write anything to the file :( but now it is creating a file so thats a step :-D.
obviously I have a data structures and other things backing this up, but I just need to get it writing. Thanks in advance
The most obvious problem is that you are opening the file several times.
Each instance of the open file will have its own file position and its
own buffer. In addition, depending on the system, either all open's but
the first will fail (Windows, I think), or the open will truncate the
file, effectively erasing any information that might have been written
to it. What you should do is have PrintToFile pass the open stream to
the functions it calls (recursively); each of these functions should
take a std::ostream& (not std::ofstream&) to receive it.
One thing I see is that you are opening the file several times. Maybe that would cause trouble. You open it first in PrintToFile then while it is still open there you open it for append in PrintBase. Then while in PrintBase you open it yet again in the call to PrintNext.
Put the ofstream as a member of the class, open it once and refer to it from all three functions.
I would use a simple if :
ofstream f (path.c_str(), ios::app);
if(!f)
{
throw std::exception(std::string("Could not open file : " + path + "for writing"));
}
//write to file here
f.close();
This way you can be sure if the file was opened succesfully or not.