I have to write a "logon" and a "logoff" function which redirect the current iostream from a function to a fstream and back.
To be more specific, I have:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
void console (istream& in, ostream& out)
{
//take command from user through console
//default input/ output stream is in/out
}
void logon (ostream& out, string filename)
{
ofstream fileout;
fileout.open(filename);
//assign this fstream fileout to ostream& out
}
void logoff (ostream& out)
{
// take current ofstream fileout
fileout.close();
// return the stream back to out
}
The program should work like this:
- User enter some commands: Output to console
- User enter logon filename command: create a file and redirect output to that file
- User enter some commands: Output to file
- User enter logoff: Close file, redirect output back to console
I know that ofstream is a part of ostream but don't know how to manipulate between the two.
Please help, any input is appreciated.
There is a trick: *streams are nothing more than facades for stream buffers which actually do work. If you replace stream buffer with another, you will redirect stream to some other place.
#include <iostream>
#include <fstream>
#include <stdexcept>
//Note that you should not ever call logon/logoff with cout with this implementation
//As it will break
void logon (std::ostream& out, const std::string& filename)
{
//*streams are just facades for stream buffers and contain a pointer to it.
std::filebuf* fout = new std::filebuf;
if(! fout->open(filename, std::ios::out))
throw std::runtime_error("File " + filename + " cannot be opened");
//by replacing rdbuf, you can redirect input/output easily
out.rdbuf(fout);
}
//Precondition: out was previously passed to logon
void logoff(std::ostream& out)
{
//Set rdbur of out to rdbuf of cout and assign previous rdbuf to fout
//This is why you should not call it with cout: we need standard output stream
//to get console buffer again. It is possible to go around this restriction,
//But you will need to do this yourself if you want.
auto fout = out.rdbuf(std::cout.rdbuf());
//Destroy previously allocated buffer.
//It will be flushed and closed automatically
delete fout;
}
int main()
{
std::ostream out(std::cout.rdbuf());
out << "Hi\n"; //Will be shown on screen
logon(out, "Test.txt");
out << "File test\n"; //Will be redirected to file
logoff(out);
out << "Screen test\n"; //Will be shown on screen again
}