How can I compose output streams, so output goes multiple places at once?
You mention having not found anything in Boost.IOStreams. Did you consider tee_device?
Same string to multiple streams
The "proper" way to do something like this is to have a stream buffer writing to multiple destinations and use this stream buffer via a std::ostream
. This way the code looks as if it writing just once but the characters are sent multiple times. Searching for "teebuf Dietmar" will find a few variations on the same theme.
To also comment on your question: Which one of the three alternatives is the fastest depends on the exact expressions you have:
- needs to evaluate the involved expressions and perform the conversions three times. Depending on what you actually do this may still be fairly fast.
- actually creates and destroys multiple streams and does multiple allocations for
std::string
. I'd expect this to be slowest. - still creates a stream (which should actually be a
std::ostringstream
) and allocates some memory. Out of your options I'd expect it to be fastest.
Using a teebuf
is probably fastest, at least, when it does some buffering but uses only fixed suze arrays, both for the buffer and the array of stream buffer pointers. Note, that you'll need to override sync()
to deal with the buffer in a timely manner, though.
To determine the actual performance you'll need to measure!
Output to two streams simultaneously
There's no built-in function that does exactly what you want; so consider writing one. An interesting aspect of printf is that it's a variadic function; fortunately, the printf family is designed to make it easy to do this sort of thing. Something like:
#include <stdio.h>
#include <stdarg.h>
int stdout_fprintf(FILE * restrict stream, const char * restrict format, ...) {
va_list ap;
va_start(ap, format);
vprintf(format, ap);
int result = vfprintf(stream, format, ap);
va_end(ap);
return result;
}
How to parametrize an output stream?
In your case you may use ternary operator:
std::ostream& ostr = (condition ?
std::cout :
(ofstr.open("file.txt"), ofstr)); // Comma operator also used
// To allow fstream initialization.
How do I output console to multiple streams at once in C#?
You could simply read that stream log it and print it out.
It depends a little on your code if you assign the output stream to the inputstream of the outfile this could be a little harder if you read the content to a buffer that should be a little easier.
About your update I would suggest that you exchange all Console
with a custom logging function e.g. a instance of MyLogger (code below) . Which writes your output to the console and to your log file.
class MyLogger {
private FileStream appLogStream;
public MyLogger() {
appLogStream = new FileStream(logFile, FileMode.Append, FileAccess.Write,
FileShare.Read);
appLogStream.WriteLine("Started at " + DateTime.Now);
}
public Write(string msg) {
Console.Write(msg);
appLogStream.Write(msg);
}
public WriteLine(string msg) {
Console.WriteLine(msg);
appLogStream.WriteLine(msg);
}
}
Doubling a stream
You could create the type of your myErr
class like this:
class stream_fork
{
std::ostream& _a;
std::ostream& _b;
public:
stream_fork( std::ostream& a, std::ostream& b)
: _a( a ),
_b( b )
{
}
template<typename T>
stream_fork& operator<<( const T& obj )
{
_a << obj;
_b << obj;
return *this;
}
// This lets std::endl work, too!
stream_fork& operator<<( std::ostream& manip_func( std::ostream& ) )
{
_a << manip_func;
_b << manip_func;
return *this;
}
};
Usage:
stream_fork myErr( std::cerr, errorString );
myErr << "Error Message" << std::endl;
How to write data to two java.io.OutputStream objects at once?
Try the Apache Commons TeeOutputStream.
Compose two Transform streams in Node.js
To compose streams, you pipe()
the first to the second, but you also have to modify pipe()
and unpipe()
so they apply to the second stream. This way additional calls to pipe()
on the composed stream will use the output of the second stream instead of the first.
function compose(s1, s2) {
s1.pipe(s2);
s1.pipe = function (dest) {
return s2.pipe(dest);
}
s1.unpipe = function (dest) {
return s2.unpipe(dest);
}
return s1;
}
var composed = compose(test(), test());
gulp.src('source/*')
.pipe( composed ) // src -> s1 -> s2
.pipe( ... ); // s2 -> ...
Write simultaneousely to two streams
User laalto is correct, but on Linux, the function you are looking for is called fopencookie
. Correcting laalto's example for Linux results in:
int my_writefn(void *cookie, const char *data, int n) {
FILE **files = (FILE **)cookie;
fwrite(data, n, 1, files[0]);
return fwrite(data, n, 1, files[1]);
}
int noop(void) { return 0; }
cookie_io_functions_t my_fns = {
(void*) noop,
(void*) my_writefn,
(void*) noop,
(void*) noop
};
FILE *files[2] = ...;
FILE *f = fopencookie((void *)files, "w", my_fns);
// ... use f as you like ...
When you write to f
, the system will execute your my_writefn
function passing it the data that was passed to fwrite
. To make things easier, you may also want to change the buffering for your file stream to be line oriented:
setvbuf(f, NULL, _IOLBF, 0);
That will buffer up the data passed to fwrite
until a newline is output or any data is read from any stream attached to the processes (e.g. stdin). NOTE: you must call sevbuf
after fopencookie
but before any data is written to the stream.
I use line buffering because I usually use fopencookie
to redirect stderr to syslog, or over a network socket, and processing line oriented data is easier and more efficient.
Related Topics
Spiral Rule and 'Declaration Follows Usage' for Parsing C and C++ Declarations
Why Does Std::Array Not Have an Constructor That Takes a Value for the Array to Be Filled With
Is There Any Guarantee of Alignment of Address Return by C++'s New Operation
What Does the Standard Say About How Calling Clear on a Vector Changes the Capacity
How to Stop Name-Mangling of My Dll's Exported Function
Who Deletes the Memory Allocated During a "New" Operation Which Has Exception in Constructor
How to Initialize a Constexpr Reference
Win32 Programming Hiding Console Window
How to Check If Enum Value Is Valid
Is Storing an Invalid Pointer Automatically Undefined Behavior
G++ "Calling" a Function Without Parenthesis (Not F() But F; ). Why Does It Always Return 1
Is It a Good Idea to Return " Const Char * " from a Function
Vector of Const Objects Giving Compile Error
Mixing C++11 Atomics and Openmp
Loading 8 Chars from Memory into an _M256 Variable as Packed Single Precision Floats