I have to print some objects fields to a file. I overloaded operator<<, and I have a method "draw" that uses it.
How can I print it to file?
ostream& operator <<(ostream& out, const Widget& obj)
{
int* colors2 = new int[3];
colors2 = obj.getbackgroundColor().getColor();
int* colors = new int[3];
colors = obj.getTextColor().getColor();
out << "[position (" << obj.getPosition().getX() << ","
<< obj.getPosition().getY() << ") ,";
out << "width (" << obj.getWidth() << ") ";
out << "height (" << obj.getHeight() << ") ,";
out << "text (" << obj.getText() << ") ,";
out << "colors (" << colors[0] << "," << colors[1] << "," << colors[2]
<< ") ,";
out << "background colors(" << colors2[0] << "," << colors2[1] << ","
<< colors2[2] << ") ,";
delete[] colors;
delete[] colors2;
return out;
}
You would want to use C++ ofstream (output file stream). You need to create an ofstream object, open the file you want to write to, and then you could use the default << operator already defined for output file stream in order to print to the file.
Take a look at the C++ documentation for ofstream; that should help you get a better understanding of file I/O.
Since you have operator<<() overloaded, use it:
std::ofstream my_file("data.s");
Widget w;
my_file << w;
The easy way to do this:
void draw(const std::string & filename)
{
std::ofstream file(filename.c_str()); //open a file for writing.
//Can use filename directly on newer compilers
file << wiget1; //use the << operator overload
file << wiget2;
...
}
The above version will open, overwrite, and close filename for every call to draw. This may not be what you want if you plan on having multiple calls to draw and the output of all those draws in the same file.
Rather than passing in the file name and opening file, you can open file elsewhere and pass it in to draw. This will allow multiple calls to draw for the same file.
Elsewhere:
std::ofstream file(filename.c_str());
new Draw:
void draw(std::ofstream & file)
{
file << wiget1; //use the << operator overload
file << wiget2;
...
}
Related
I am trying to logg my events so i thought of using ostringstream to save the output and then send it to a function where i print the output on screen and on file fstream fileOut. It wont work, it just gives me random numbers and seem not to output all new outputs on the same file but just creates a new file everytime and deletes what was on it before. How do i do this?
where the print happens:
void Event::output(ostringstream* info) {
std::cout << info << std::endl;
fileOut << info << std::endl;
}
where the output happens:
ostringstream o;
if (time < SIM_TIME) {
if (status->tryAssemble(train)) {
Time ct;
ct.fromMinutes(time);
o << ct << " Train [" << train->getTrainNumber() << "] ";
Time t(0, DELAY_TIME);
o << "(ASSEMBLED) from " << train->getStart() << " " << train->getScheduledStartTime() <<
" (" << train->getStartTime() << ") to " << train->getDest() << " " << train->getScheduledDestTime() <<
" (" << train->getDestTime() << ") delay (" << train->getDelay() << ") speed=" << train->getScheduledSpeed() <<
" km/h is now assembled, arriving at the plateform at " << train->getStartTime() - t << endl << endl;
fileOut.open("testfile.txt", std::ios::out);
if (!fileOut.is_open())
exit(1); //could not open file
output(&o);
train->setStatus(ASSEMBLED);
time += ASSEMBLE_TIME;
Event *event = new ReadyEvent(simulation, status, time, train);
simulation->addEvent(event);
It wont work, it just gives me random numbers
You are passing the ostringstream to your function by pointer. There is no operator<< that takes an ostringstream* pointer as input and prints its string content. But there is an operator<< that takes a void* as input and prints the memory address that the pointer is pointing at. That is the "random numbers" you are seeing. ANY type of pointer can be assigned to a void* pointer.
You need to dereference the ostringstream* pointer to access the actual ostringstream object. Even so, there is still no operator<< that takes an ostringstream as input. However, ostringstream has a str() method that returns a std::string, and there is an operator<< for printing a std::string:
void Event::output(ostringstream* info) {
std::string s = info->str();
std::cout << s << std::endl;
fileOut << s << std::endl;
}
That being said, you should pass the ostringstream by const reference instead of by pointer, since the function does not allow a null ostringstream to be passed in, and it does not modify the ostringstream in any way:
void Event::output(const ostringstream &info) {
std::string s = info.str();
std::cout << s << std::endl;
fileOut << s << std::endl;
}
...
output(o);
seem not to output all new outputs on the same file but just creates a new file everytime and deletes what was on it before.
That is because you are not opening the file with either the app or ate flag 1, so it creates a new file each time, discarding the contents of any existing file. If you want to append to an existing file instead, you need to either:
use the ate flag to "seek to the end of stream immediately after open":
fileOut.open("testfile.txt", std::ios::out | std::ios::ate);
use the app flag to "seek to the end of stream before each write":
fileOut.open("testfile.txt", std::ios::out | std::ios::app);
1: if fileOut is a std::ofstream, you do not need to specify std::ios::out explicitly.
// Update the server status xml
string filelocation ("/var/www/html/index.xml");
string firstline ("<server>\n");
string secondline ("\t<current>" + msg.getCount() + "</current>\n");
string thirdline ("\t<highest>" + "--" + "</highest>\n");
string fourthline ("\t<status>Online</status>\n")
string finalline ("</server>");
fstream file;
file.open(filelocation);
file.write(firstline + secondline + thirdline + fourthline + finalline);
string updateFlush ("Server Status updated.");
printf("%s\n", updateFlush);
file.close();
Note that msg.getCount() is a function in the same file to get player count from the central server.
Gives out errors about an operands const char*. Something to do with + or -
Thanks
Take a look at the line
string secondline ("\t<current>" + msg.getCount() + "</current>\n");
"\t<current>" is a const char *
msg.getCount() looks like an int or size_t
</current>\n again is a const char *
Adding a const char * to an int or size_t creates a new const char * pointing to a different address.
The same happens in the line
string thirdline ("\t<highest>" + "--" + "</highest>\n");
Here you are adding pointers together. The result is a pointer pointing to a more or less random address.
And in these two lines:
string updateFlush ("Server Status updated.");
printf("%s\n", updateFlush);
You are creating a C++ string-object and trying to print it using a C print function with a format string that requires a char *.
You are mixing C and C++ or stream based I/O with conventional I/O.
In current C++ you should do it this way:
string filelocation ("/var/www/html/index.xml");
fstream file;
file.open(filelocation);
file
<< "<server>\n"
<< "\t<current>" << msg.getCount() << "</current>\n"
<< "\t<highest>" << "--" << "</highest>\n"
<< "\t<status>Online</status>\n"
<< "</server>";
string updateFlush ("Server Status updated.");
cout << updateFlush << std::endl;
file.close();
Or even more readable:
auto file = std::ofstream("/var/www/html/index.xml");
file
<< "<server>" << std::endl
<< "\t<current>" << msg.getCount() << "</current>" << std::endl
<< "\t<highest>" << "--" << "</highest>" << std::endl
<< "\t<status>Online</status>" << std::endl
<< "</server>";
file.close();
std::cout << "Server status updated." << std::endl;
If operating with streams use std::endl to output a newline. It outputs the correct newline for the operation system (CRLF or LF or whatever) and it flushes the stream.
To use std::cout you have to include <iostream> and for std::ofstream include <fstream>.
If you like it short, you could even do this:
std::ofstream("/var/www/html/index.xml")
<< "<server>" << std::endl
<< "\t<current>" << msg.getCount() << "</current>" << std::endl
<< "\t<highest>" << "--" << "</highest>" << std::endl
<< "\t<status>Online</status>" << std::endl
<< "</server>";
std::cout << "Server status updated." << std::endl;
Let's say I have a program that does the follow:
for (i=1; i<10; i++)
{
computeB(i);
}
where the computeB just outputs a list of values
computeB(int i)
{
char[6] out_fname="output";
//lines that compute `var` using say, Monte Carlo
string fname = out_fname + (string)".values";
ofstream fout(fname.c_str());
PrintValue(fout,"Total Values", var);
}
From another file:
template <class T>
void PrintValue(ofstream & fout, string s, T v) {
fout << s;
for(int i=0; i<48-s.size(); i++) {
fout << '.';
}
fout << " " << v << endl;
}
Before implementing that loop, computeB just outputted one file of values. I now want it to create multiple values. So if it originally created a file called "output.values", how can I write a loop so that it creates "output1.values", "output2.values", ..., "output9.values"?
EDIT: I forgot to mention that the original code used the PrintValue function to output the values. I originally tried to save space and exclude this, but I just caused confusion
Disregarding all the syntax errors in your code ...
Use the input value i to compute the output file name.
Use the file name to construct an ofstream.
Use the ofstream to write var to.
Here's what the function will look like:
void combuteB(int i)
{
char filename[100];
sprintf(filename, "output%d.values", i);
ofstream fout(filename);
fout << "total values";
fout << " " << var << endl; // Not sure where you get
// var from. But then, your
// posted code is not
// exactly clean.
}
You can use std::to_string() to convert from an int to a string:
void computeB(int i)
{
if (std::ofstream fout("output" + std::to_string(i) + ".values"))
fout << "total values" << " " << var << '\n';
else
throw std::runtime_error("unable to create output file");
}
I want to add new string at the end of file when I register new user its overwrite the previous values.
write.open("usersinfo.txt");
if (write.is_open())
{
write << username << "\t" << password << "\t" << cnpassword << "\t" << email << "\t" << number << "\n\n";
cout << "\n\n\nPlease Wait Your Data Is Saving";
for(int i=0;i<10;i++)
{
cout << ".";
Sleep(400);
}
cout << "\n\n\t\t\tSign Up Successfull";
write.close();
}
Use
write.open("usersinfo.txt", std::ios::app);
to open the file with the write pointer already at the end (i.e., if you want to append to the file).
EDIT: Upon double-checking the standard, the first edit turned out to be unnecessary. std::ios::app implies std::ios::out (27.9.1.4).
you should open your file in append mode so you can add your new text after what you have writen before.
The right way is
write.open("usersinfo.txt", std::ios::app);
instead
write.open("usersinfo.txt"); is equal to
write.open("usersinfo.txt", std::ios::out);
I'm trying to convert a string streamed phone lookup program into file streamed.. I'm missing something, but I'm stuck.. what members can I use in the ofstream process to get this working?
ofstream& process (ofstream &os, vector<PersonInfo> people)
{
// for each entry in people
for (vector<PersonInfo>::const_iterator entry = people.begin();
entry != people.end(); ++entry) {
ofstream formatted, badNums; // objects created on each loop
// for each number
for (vector<string>::const_iterator nums = entry->phones.begin();
nums != entry->phones.end(); ++nums) {
if (!valid(*nums)) {
badNums << " " << *nums; // string in badNums
} else
// ``writes'' to formatted's string
formatted << " " << format(*nums);
}
if (badNums.empty()) // there were no bad numbers
os << entry->name << " " // print the name
<< formatted.str() << endl; // and reformatted numbers
else // otherwise, print the name and bad numbers
cerr << "input error: " << entry->name
<< " invalid number(s) " << badNums.str() << endl;
}
return os;
}
First, you don't want an ofstream, except at the point you're opening
the file (creating the instance). The output stream interface is
defined by std::ostream; std::ofstream derives from this, as does
std::ostringstream (output can become an std::string), and in most
applications, a couple of others written by the local programmers. In
your case (if I've understood the problem correctly), what you want is:
std::ostream& process( std::ostream& os,
std::vector<PersonInfo> const& people )
// Note the use of a const reference above. No point
// in copying the entire vector if you're not going to
// modify it.
{
for ( std::vector<PersonInfo>::const_iterator entry = people.begin();
entry != people.end();
++ entry ) {
std::ostringstream formatted;
std::ostringstream badNums;
// ...
if ( badNums.str().empty() ) {
os << ... << formatted.str() << std::endl;
} else {
os << ... << badNums.str() << std::endl;
}
}
return os;
}
Note the different types: std::ostream formats output, independently
of the destination type. std::ofstream derives from it, and provides
a file as destination. std::ostringstream derives from it, and
provides a std::string as destination type. And the std::ostream
takes a std::streambuf* as argument, and you provide the destination
type.
You never associate a file with ostream, so the compiler doesn't know what to do with the data you write into it.
ofstream& process (ofstream &os, vector<PersonInfo> people)
{
os.open("Data.txt"); //open file to be used
if(!os.is_open())
std::cerr << "Error opening file!\n";
//rest of code goes here
}
EDIT: after reading through your program again, i noticed you're using ofstream wrong. Ofstream is for opening and writing FILES.The program has a lot of syntax and logical errors i would read up on it more here.
It looks like you don't need to use ofstreams for the internal parts of this function. In fact you don't need to use streams at all, a std::string would do:
ofstream& process (ofstream &os, vector<PersonInfo> people)
{
// for each entry in people
for (vector<PersonInfo>::const_iterator entry = people.begin();
entry != people.end(); ++entry) {
string formatted, badNums; // objects created on each loop
// for each number
for (vector<string>::const_iterator nums = entry->phones.begin();
nums != entry->phones.end(); ++nums) {
if (!valid(*nums)) {
badNums += " " + *nums; // string in badNums
} else
// ``writes'' to formatted's string
formatted += " " + format(*nums);
}
if (badNums.empty()) // there were no bad numbers
os << entry->name << " " // print the name
<< formatted << endl; // and reformatted numbers
else // otherwise, print the name and bad numbers
cerr << "input error: " << entry->name
<< " invalid number(s) " << badNums << endl;
}
return os;
}