Obtain a Std::Ostream Either from Std::Cout or Std::Ofstream(File)

Obtain a std::ostream either from std::cout or std::ofstream(file)

std::streambuf * buf;
std::ofstream of;

if(!condition) {
of.open("file.txt");
buf = of.rdbuf();
} else {
buf = std::cout.rdbuf();
}

std::ostream out(buf);

That associates the underlying streambuf of either cout or the output file stream to out. After that you can write to "out" and it will end up in the right destination. If you just want that everything going to std::cout goes into a file, you can aswell do

std::ofstream file("file.txt");
std::streambuf * old = std::cout.rdbuf(file.rdbuf());
// do here output to std::cout
std::cout.rdbuf(old); // restore

This second method has the drawback that it's not exception safe. You possibly want to write a class that does this using RAII:

struct opiped {
opiped(std::streambuf * buf, std::ostream & os)
:os(os), old_buf(os.rdbuf(buf)) { }
~opiped() { os.rdbuf(old_buf); }

std::ostream& os;
std::streambuf * old_buf;
};

int main() {
// or: std::filebuf of;
// of.open("file.txt", std::ios_base::out);
std::ofstream of("file.txt");
{
// or: opiped raii(&of, std::cout);
opiped raii(of.rdbuf(), std::cout);
std::cout << "going into file" << std::endl;
}
std::cout << "going on screen" << std::endl;
}

Now, whatever happens, std::cout is in clean state.

ostream: class that outputs either on cout or on a file

I would try to split here the stream creation with the stream usage. std::ostream is already polymorphic, so as long as you pass a reference or pointer to the function that uses the stream, all good.

For the creation, I would go for creating the stream in the heap, as the post you linked to suggests. However, doing explicit memory management (raw new/delete) is dangerous, so I would use a smart pointer, like std::unique_ptr:

#include <fstream>
#include <memory>

struct ConditionalDeleter
{
bool must_delete;
void operator()(std::ostream* os) const { if (must_delete) delete os; }
};

using OstreamPtr = std::unique_ptr<std::ostream, ConditionalDeleter>;

OstreamPtr create_stream(bool to_file)
{
if (to_file)
return OstreamPtr { new std::ofstream {"myfile.txt"}, ConditionalDeleter {true} };
else
return OstreamPtr { &std::cout, ConditionalDeleter {false} };
}

void use_stream(std::ostream& os)
{
os << "Hello world!" << std::endl;
}

int main()
{
auto streamptr = create_stream(false);
use_stream(*streamptr);
}

I've used a custom deleter with std::unique_ptr. The reason for that is: if we are using the file, I want the stream to be deleted; but std::cout is a global object, which we must not delete. The agreement here is that when your OstreamPtr gets destroyed, ConditionalDeleter::operator() will get called. *streamptr returns you a reference to your std::ostream, which you can use as you want.

Please note you need C++11 support to use this solution.

How to use std::cout or std::ofstream as an input of a single function?

Don't use std::ofstream in write. Use std::ostream.

void write(std::ostream& o)
{
o << "Some text..." << std::endl;
}

Also,

 auto outputStream = std::ofstream(std::cout);
write();

is not right. Just use.

 write(std::cout);

I'd change the first of the if block too.

if (argc == 2){
std::ofstream outputStream(argv[1]);
write(outputStream);
}
else{
write(std::cout);
}

how to temporarily use std::cout in place of std::ofstream

Think of std::cout of what it actually is: an object. It is just that:

The global objects std::cout and std::wcout control output to […]

So when you say that you want to temporarily use std::cout in place of std::ofstream you're mixing apples (object std::cout) with oranges (class std::ofstream).

What you want to do, instead, is to use std::cout instead of an object of class std::ofstream.

But std::cout is not of class std::ofstream, so error can't hold it; it is of class std::ostream, which is a superclass of the former.

Therefore, as suggested in a comment, you can make error/event references to an object of that class, std::ofstreamstd::ostream&, and initialize them with std::cout or with std::ofstream{"filename.txt"} via an appropriate constructor of the logging_class.

Good practice to write binary stream to either a file or stdout

My version would something more akin to this:

#include <iostream>
#include <fstream>

void function2(bool bWriteConsole)
{
std::ofstream outfile;

if (!bWriteConsole)
outfile.open("./hello.bin", std::ofstream::binary | std::ofstream::out);

double dValue = 1.2345;

// writing out
std::ostream& out = bWriteConsole ? std::cout : outfile;
out.write(reinterpret_cast<char*>(&dValue), sizeof dValue);
out.flush();
}

Writing code is 2 lines, 3 if you really want to flush. outfile.close() would flush as well, so there is no harm in flushing unconditionally versus your approach. File will get closed when outfile goes out of scope so it doesn't have to be written unless you really want to manually close the file before some further processing. Here it's superfluous (RAII goodness comes into play here).

Aaand maybe refactor writing:

template<typename T>
void dump(T val, std::ostream& out ) {
out.write(reinterpret_cast<char*>(&val), sizeof val);
out.flush();
}

void function2(bool bWriteConsole)
{
std::ofstream outfile;

if (!bWriteConsole)
outfile.open("./hello.bin", std::ofstream::binary | std::ofstream::out);

double dValue = 1.2345;
dump(dValue, bWriteConsole ? std::cout : outfile);
// writing out
}

Check if ostream object is cout or ofstream, c++

It's possible by checking the stream's 'identity': if ( &out == &cout ) ....

However, I'm in doubt on the usefullness of this test. If your function can handle any output stream, why bother about what stream it is using?

Proper way to create ostream to file or cout

You create tmp with std::ostream tmp(buf); and store the address of it in out with this->out = &tmp;. However, tmp will go out of scope at the end of the constructor and the pointer will no longer be pointing at a valid object.

What you should do instead is make out not a std::ostream* but simply a std::ostream:

std::ostream out;

Then in your constructor, once you've got the buf ready, you can give it to out by doing out.rdbuf(buf);.


Response to edit:

The std::ostream doesn't have a default constructor - it has to take a buffer pointer. My mistake. However, the fix is simple. Use your constructor's member initialization list to pass a null pointer (nullptr in C++11, 0 or NULL in C++03):

Log::Log(const char *file)
: out(nullptr)
{
// ...
}

How to switch between std::ofstream and std::cerr

You will have to dynamically-allocate your streams:

std::unique_ptr<std::ostream> get_stream() {
bool flag = time(0) % 2;
return ( flag
? std::make_unique<std::ostream>(std::cerr.rdbuf())
: std::make_unique<std::ofstream>("somefile.txt")
);
}

int main() {
auto logger {get_stream()};
*logger << "Just testing, everything is fine."
<< std::endl;
}

Copy the contents of std::ofstream into an std::string

No. "the contents of this std::ofstream" is nonsensical. The file has contents, the stream is a handle that represents writing to the file.

Either flush ofs and read the file, or use std::ostream & in place of std::ofstream &.



Related Topics



Leave a reply



Submit