Assign ofstream to ostream

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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#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
}

Last edited on
Topic archived. No new replies allowed.