C++ ostream and ofstream conversions - c++

My code has an ostream object that is accumulated by various modules and ultimately displayed to the console. I'd like ALSO to write this ostreamobject to a file, but do I have to rewrite all of that code using an ofstream object instead, or is there a way to convert one to the other (perhaps via a stringstream?)
For example, many of my existing functions look like
ostream& ClassObject::output(ostream& os) const
{
os << "Details";
return os;
}
Can I call this function with an ofstream object as the argument and have that ofstream object accumulate information instead?

Yes, you can. That's the point in the OO concept called subtype polymorphism. Since ofstream derives from ostream, every instance of ofstream is at the same time an instance of ostream too (conceptually). So you can use it wherever an instance of ostream is expected.

ofstream derived from ostream so
Just add some code in main.cpp
#include "ClassObject"
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ClassObject ob;
cout << ob; // print info to console window
// save info to .txt file
ofstream fileout;
fileout.open("filename.txt", ios::app);
fileout << ob;
fileout.close();
return 0;
}

Related

overwrite file only at the first actual write

I would like to open a file for writing, such that the file is wiped and written over at the first write instruction. That is, the file should retain its contents when opened, and only at the first insertion is actually written over.
Using std::fstream, if I use the mode std::ios_base::out, the file is immediately wiped as soon as the constructor is called
#include <fstream>
int main()
{
std::fstream f("test.txt", std::ios_base::out);
// Now test.txt is empty
f << "hello";
}
This behavior would be ok if test.txt does not exists. But if test.txt exists, I would like to have its contents preserved until I write to it. If I open it with
std::fstream f("test.txt", std::ios_base::out | std::ios_base::in);
indeed an existing file is still preserved, and it is written over only on f << "hello".
However, if the file exists and contains more data then the string "hello", then f << "hello" will only overwrite the first 5 characters. I would like the file to be wiped, as if it were opened with std::ios_base::out, but only when I execute f << "hello".
Context
The problem arises with a routine like this:
void do_something(std::ostream& s)
{
//... very long computation
s << "some infos" << std::endl;
}
I call do_something passing to it a stream, which could or could not be a file. If it is a file, I would like to be able to inspect test.txt before the computation is done.
One possibility could be to wrap a fstream in a new object that actually opens the file only when operator<< is called, something like
#include <fstream>
class myfstream {
std::fstream m_f;
std::string m_filename;
public:
myfstream(std::string& filename) : m_filename{filename} { }
template <typename U>
myfstream& operator<<(const U& s) { if (!m_f.is_open()) m_f.open(m_filename, std::ios_base::out); m_f << s; return *this; }
};
The drawback of this solution is the lack of flexibility: if the routine do_something does something else than just calling operator<<, one has to define all the other members of std::ostream, to mimick its behavior. Also, to retain flexibility do_something has to be declared as
template <typename S>
void do_something(S& o);
Is there a better solution? Would it be possible, say, given a fstream to delete all data after the current position of the output indicator?
Update
Apparently, a possible solution is to get the actual write position with tellp() and after closing the file, resize it. See following code:
#include <fstream>
#include <filesystem>
#include <iostream>
int main()
{
typename std::fstream::pos_type size;
{
char d;
std::fstream f("test.txt", std::ios_base::in | std::ios_base::out);
std::cin >> d; // Just to pause
f << "hello";
size = f.tellp();
}
char d;
std::cin >> d; // Just to pause
std::filesystem::resize_file("test.txt", size);
return 0;
}
(The std::cin are there only to pause and be able to check the actual contents of the file).
Testing the program, after the first "pause" the file is still intact. After the second pause, the first characters have been overwritten with the string "hello", but any text following that is still untouched. Finally, resize_file shrinks the file to the actual length of the written string.
The above code does an implicit conversion between a pos_type as returned from tellp() and a std::uintmax_t as required from resize_file.
Is this conversion safe?

Copy all std::cout messages to log file? [duplicate]

I need redirect the copy of std::cout to the file. I.e. I need see the output in console, and in file. If I use this:
// redirecting cout's output
#include <iostream>
#include <fstream>
using namespace std;
int main () {
streambuf *psbuf, *backup;
ofstream filestr;
filestr.open ("c:\\temp\\test.txt");
backup = cout.rdbuf(); // back up cout's streambuf
psbuf = filestr.rdbuf(); // get file's streambuf
cout.rdbuf(psbuf); // assign streambuf to cout
cout << "This is written to the file";
cout.rdbuf(backup); // restore cout's original streambuf
filestr.close();
return 0;
}
then I write string to the file, but I see the nothing in console. How can I do it?
The simplest you can do is create an output stream class that does this:
#include <iostream>
#include <fstream>
class my_ostream
{
public:
my_ostream() : my_fstream("some_file.txt") {}; // check if opening file succeeded!!
// for regular output of variables and stuff
template<typename T> my_ostream& operator<<(const T& something)
{
std::cout << something;
my_fstream << something;
return *this;
}
// for manipulators like std::endl
typedef std::ostream& (*stream_function)(std::ostream&);
my_ostream& operator<<(stream_function func)
{
func(std::cout);
func(my_fstream);
return *this;
}
private:
std::ofstream my_fstream;
};
See this ideone link for this code in action: http://ideone.com/T5Cy1M
I can't currently check if the file output is done correctly though it shouldn't be a problem.
You could also use boost::iostreams::tee_device. See C++ "hello world" Boost tee example program for an example.
Your code does not work, because it is the streambuf that determines where the output written to a stream end up, not the stream itself.
C++ does not have any streams or streambufs that support directing the output to multiple destinations, but you could write one yourself.

(ostream& outs) in class function parameters C++

What does the parameter in a class function ostream& outs mean?
e.g
void BankAccout::output(ostream& outs){
outs.setf(ios::fixed);
outs.setf(ios::showpoint);
outs.precision(2);
outs<<"account balance $"<<balance<<endl;
outs<<"Interest rate"<<interest_rate<<"%"<<endl;
}
and why is it that for outputing information onto ouput,it no longer uses cout,but now uses outs?
Make yourself familiar with streams: http://www.cplusplus.com/reference/iolibrary/
Basically ostreams are streams to write into, that output the data somewhere. cout is also an ostream. But you can also open a file as an ostream. So this function lets you decide where the data should be written to. If you want the data written in the terminal you pass cout as the argument. If you want it in a file, you open a file as an ostream and pass that to the function instead.
Just for example:
int main(void)
{
BankAccount *ba = new BankAccount();
ba->output(cout); //prints to terminal
std::ofstream ofile; //ofstream is derived from ostream
ofile.open("test.txt");
ba->output(ofile); //will output to the file "test.txt"
delete ba;
return 0;
}

SIGABRT in binary read/write

I wrote a very small code snippet and have already gotten the following error:
malloc: *** error for object 0x100100080: pointer being freed was not allocated
Problem is, I have no idea what pointer the compiler's talking about. I pass a variable in by address to the read/write functions, but I never freed it as far as I know. Where's the error in my code? I ran it with Leaks and Zombies, but got nothing.
Here's my program:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Bank
{
private:
string __name;
public:
Bank()
{
__name = "";
}
Bank(string name)
{
__name = name;
}
string getName() const { return __name; }
};
int main (int argc, char * const argv[])
{
Bank bank("Bank of America");
Bank bank2;
cout << "Bank1: " << bank.getName() << endl;
string filename = bank.getName() + ".bank";
ofstream fout(filename.c_str(), ios::binary);
if (fout.good())
fout.write((char *)&bank, sizeof(bank));
fout.close();
ifstream fin(filename.c_str(), ios::binary);
if (fin.good())
fin.read((char *)&bank2, sizeof(bank2));
fin.close();
cout << "Bank2: " << bank2.getName() << endl;
return 0;
}
You can't read an object that contains a std::string (or anything that's not Plain Ol' Data) with fin.read()--
The object is read and written as a stream of bytes, but std:string contains a pointer to memory that is stored elsewhere and is not written with your fout.write() and is not initialized properly with your fin.read()
It is because it is not initialized properly with your fin.read() that you are getting the heap error; when the object goes out of scope, the destructor of the improperly initialized std::string is being called, and trying to free memory that it doesn't own.
You probably want to write a custom i/o method for your object and save or load it piece-by-piece. For a shortcut to doing this, use the Boost serialization library.
Because your Bank class contains a std::string, you can't read/write it as binary like you are thinking. A std::string has internal pointers. If you write it as binary, you are just going to be writing pointers and not the actual string contents. Likewise, when you read the string, you are going to be reading a pointer. In this case, you end up making both your bank and bank2 objects have strings which point to the same memory, so when that memory is freed it gets freed twice.
You'll need to have some other way of writing your bank data to a file. In this case, a simple ASCII file with the bank name would be fine.
You cannot do what you are doing, simply because std::string cannot be copied like that. Internally a string object allocates memory and a simple copy of the outer structure doesn't do what you expect.
You need to serialize this structure properly.
Don't use underscores, please
Pass objects by reference: Bank(string& name), please
This is evil: fout.write((char *)&bank, sizeof(bank));
You may want to write << and >> ostream operators of your Bank class.
For example:
friend std::ostream& operator<<(std::ostream &out, const Bank& b);
friend std::istream& operator>>(std::istream &out, const Bank& b);
Members functions write of ostream and read of istream are specifically designed to input and output binary data. If you do want to manipulate binary data, use the following:
ifstream fin(filename.c_str(), ios::in|ios::binary|ios::ate);
size = fin.tellg();
memblock = new char [size];
fin.seekg(0, ios::beg);
if (fin.good()){
fin.read(memblock, size);
fin.close();
}
delete[] memblock;

operator overloading

How can I overload << operator (cout) so that it can be written to a file. Whenever << occurs it should be appended to the file i.e. instead of displaying on the screen it should be written to the file.
can i get a code for this...i am new to c++ and code written by me is not working..
Normally you provide std::ostream& operator<<(std::ostream&, const YourClass&) for your class and write to a file stream as follows:
std::ofstream ofs("out");
ofs << yourObject;
where yourObject is an object of YourClass.
Your overloaded << operator shouldn't care what kind of output stream that it goes to or whether it's appending or overwriting. It takes a std::ostream& and writes to it. If it's used with cout, then it's written to the console. If it's used with a std::ofstream, then it writes to a file. If that std::ofstream was opened to overwrite, then it overwrites. If it was opened to append, then it appends.
All that your overloaded << operator should care about is that it's writing to an output stream. What that stream represents is irrelevant.
This overloading is already done for the C++ file stream. The name cout means console out and the spirit is, it will output to console.
One thing you could do is use freopen(), to redirect all output to a file.
If you just want to send text to a file rather than the console, then std::ofstream is your friend. Like cout, your instance of ofstream shares the behaviour of ostream which already has a suitable << operator for strings and can be used exactly as cout. Here's an example:
#include <fstream>
int main()
{
std::ofstream fout("somefile.txt");
fout << "Some text" << std::endl;
return EXIT_SUCCESS;
}
Compile and run and you'll find that you have a new file in the current working directory:
% cat somefile.txt
Some text
If you need to stream an object that doesn't have operator << overloaded for std::ostream, then you you will need to overload the operator, like this:
std::ostream& operator <<(std::ostream& os, const SomeClass& instance)
{
instance.print(os);
return os;
}
You'll need void SomeClass::print(std::ostream& os) defined to send its private data to os (this saves you making the << a friend of your class).
Were you talking purely about cout, then this isn't "operator overloading", this is stream redirection. But, yes, it is possible (too) by setting the associated stream buffer using std::basic_ios::rdbuf().
Here is my solution from "Redirecting in C++":
#include <iostream>
#include <fstream>
class scoped_cout_redirector
{
public:
scoped_cout_redirector(const std::string& filename)
:backup_(std::cout.rdbuf())
,filestr_(filename.c_str())
,sbuf_(filestr_.rdbuf())
{
std::cout.rdbuf(sbuf_);
}
~scoped_cout_redirector()
{
std::cout.rdbuf(backup_);
}
private:
scoped_cout_redirector();
scoped_cout_redirector(const scoped_cout_redirector& copy);
scoped_cout_redirector& operator =(const scoped_cout_redirector& assign);
std::streambuf* backup_;
std::ofstream filestr_;
std::streambuf* sbuf_;
};
int main()
{
{
scoped_cout_redirector file1("file1.txt");
std::cout << "This is written to the first file." << std::endl;
}
std::cout << "This is written to stdout." << std::endl;
{
scoped_cout_redirector file2("file2.txt");
std::cout << "This is written to the second file." << std::endl;
}
return 0;
}