Now to my question. I wonder how I might be able to direct cout to not only
print to the screen but also write to a file. How do you use redirection for
that?
Thanks a lot
Jim.
> Now to my question. I wonder how I might be able to direct cout to not only
> print to the screen but also write to a file. How do you use redirection for
> that?
File redirection is a function of the command shell, not of C++. You need to
examine which command shell you are using. The command shell that comes with
Windows does not support the function that you are looking for. The command shells
for UNIX do support it. If you are on Windows you can get the bash shell from
various places to use in place of COMMAND.COM.
--
Jim Cobban jco...@magma.ca
34 Palomino Dr.
Kanata, ON, CANADA
K2M 1M1
+1-613-592-9438
TiTi
Read "Homesteeding the Noosphere" by Eric Raymond (you should find this
paper on his homepage which in turn can be found via
<http://www.opensource.org/>). Apart from mere kindness, this describes
more motives, at least it describes some motivation which I can find for
myself. I have also other motives which are rather commercial: You can
sell a good reputation.
> Now to my question. I wonder how I might be able to direct cout to
> not only print to the screen but also write to a file. How do you use
> redirection for that?
I'm not clear how you really want to redirect 'cout' but since you are
posting to a C++ newsgroup I'm assuming that you don't want to use the
shell redirection mechanism (eg. on POSIX systems something like
"program | tee file"; see the man page of tee(1) for more information).
Instead, I'm assuming you want to use only C++ mechanisms.
Your question actually consists of two separate parts:
- How to redirect 'std::cout'?
- How to write to more than one stream at once?
The answer to the first question is to pass around a reference to an
'std::ostream' and write to this stream. In this case you would just
pass 'std::cout' from something like 'main()' and that's it. Sometimes
this is not appropriate, eg. because the code is mostly already existing
and uses 'std::cout' all over. In this case you can just replace the
stream buffer used by 'std::cout' with a suitable other stream buffer.
Since this question is answered first, I'm just directing 'std::cout' to
a file. It can as well be directed to the stream buffer described below:
int main() {
std::streambuf* cout_sbuf = std::cout.rdbuf(); // save original sbuf
std::ofstream fout("cout.txt");
std::cout.rdbuf(fout.rdbuf()); // redirect 'cout' to a 'fout'
// ...
std::cout.rdbuf(cout_sbuf); // restore the original stream buffer
}
Restoring the original stream buffer is necessary because the stream
buffer to which 'std::cout' was redirected is destroyed at the end of
'main()'. Thus, writing stuff to 'std::cout' after exiting from 'main()'
that is from a destructor of an object with static linkage would fail.
Restoring the original stream buffer avoids this problem.
This was easy so far. Now for the more interesting part of writing to
multiple destinations at once: This is done using a new stream buffer
which writes to two destinations. To do so, the new stream buffer, call
it 'teebuf', writes to two stream buffers it gets at construction time.
For simplicity, the buffer in the example is unbuffered but for better
performance it is reasonable to add a buffer (this would, however, make
the code significantly more complex):
#include <streambuf>
class teebuf: public std::streambuf {
public:
typedef std::char_traits<char> traits_type;
typedef traits_type::int_type int_type;
teebuf(std::streambuf* sb1, std::streambuf* sb2):
m_sb1(sb1), m_sb2(sb2) {}
private:
int_type overflow(int_type c) {
if (!traits_type::eq_int_type(c, traits_type::eof()) {
c = sb1->sputc(c);
if (!traits_type::eq_int_type(c, traits_type::eof()))
c = sb2->overflow(c);
return c;
}
else
return traits_type::not_eof(c);
}
int sync() {
int rc = sb1->sync();
if (rc != -1)
rc = sb2->sync();
return rc;
}
};
This is a very simple unbuffered write-only stream buffer. Every
received character is immediately sent to the two underlying stream
buffers: If the method 'sputc()' cannot put a character into the buffer,
it calls 'overflow()' to write this character and give the stream buffer
a chance to set up a new buffer. Since there is no buffer to be set up,
the character is just written. There is an asymmetry between the two
used stream buffers: If writing to the first character fails, it is not
even attempted to write to the second stream buffer. This can be changed
but is rarely a problem because write error are rare anyway (that is, if
there is a problem it becomes a huge problem...). There is a similar
asymmetry for the 'sync()' function. The purpose of this function is to
flush buffers. Since the 'teebuf' does not have a buffer, this request
is just forwarded to the two underlying stream buffers.
Here is a sample use of this stream buffer:
#include "teebuf.h"
#include <iostream>
#include <fstream>
int main() {
std::streambuf* cout_sbuf = std::cout.rdbuf();
std::ofstream fout("file.txt");
teebuf teeout(std::cout.rdbuf(), fout.rdbuf());
std::cout.rdbuf(&teeout);
std::cout << "hello, world\n";
std::cout.rdbuf(cout_sbuf);
}
This program should write "hello, world\n" to both 'std::cout' and the
file "file.txt".
PS: It took me about 25 minuts to answer the question...
--
<mailto:dietma...@claas-solutions.de>
homepage: <http://www.informatik.uni-konstanz.de/~kuehl>
Sent via Deja.com http://www.deja.com/
Before you buy.
Hi,
See below.
Hope this helps.
Alex
//#########################################################
// File#1 of 3 : echo_file.H
//------------------- C++ code : BEGIN -------------------
//###########
// echo_file.H
//###########
#ifndef echo_file_H
#define echo_file_H
#include <string>
#include <iostream.h>
#include <fstream.h>
#include <assert.h>
#define DEFAULT_OutFileName "Default.out"
class echo_file
{
private:
ofstream OutFile;
public:
echo_file ()
{
assert (!OutFile.is_open ());
OutFile.open(DEFAULT_OutFileName);
if (!OutFile.is_open ())
{
cout << "Cannot open "
<< DEFAULT_OutFileName
<< endl;
exit (1);
}
}
void setFileName (char const * const fn)
{
OutFile.close ();
assert (!OutFile.is_open ());
OutFile.open(fn);
if (!OutFile.is_open ())
{
cout << "Cannot open "
<< fn
<< endl;
exit (1);
}
};
~echo_file()
{
OutFile.close();
assert (!OutFile.is_open ());
};
echo_file& operator<< (ostream& v (ostream&))
{
cout << v;
OutFile << v;
return *this;
}
template <class T> echo_file& operator<< (const T& v)
{
cout << v;
OutFile << v;
return *this;
}
};
extern echo_file tout;
#endif
//---------------------------------------------------------
// File#1 of 3 : echo_file.H
//------------------- C++ code : END ----------------------
//#########################################################
// File#2 of 3 : echo_file.C
//------------------- C++ code : BEGIN -------------------
#include "echo_file.H"
echo_file tout;
//---------------------------------------------------------
// File#2 of 3 : echo_file.C
//------------------- C++ code : END ----------------------
//#########################################################
// File#3 of 3 : echo_main.C
//------------------- C++ code : BEGIN -------------------
//###########
// echo_main.C
//###########
#include "echo_file.H"
int main()
{
string s1 = "AAAAA";
char* s2 = "BBBBB";
int i1 = 111;
tout << s1 << endl;
tout << s2 << endl;
tout << "CCCCC" << endl;
tout << i1 << endl;
tout << 222 << endl;
tout.setFileName ("AAA.out");
tout << "HELLO" << endl;
tout << 33333 << endl;
return 0;
}
//---------------------------------------------------------
// File#3 of 3 : echo_main.C
//------------------- C++ code : END ----------------------
//#########################################################
//------------------- Running Results : BEGIN -------------
// Screen
AAAAA
BBBBB
CCCCC
111
222
HELLO
33333
// OutFile : Default.out
AAAAA
BBBBB
CCCCC
111
222
// OutFile : AAA.out
HELLO
33333
//------------------- Running Results : END ---------------
//#########################################################
//------------------- Compiler & System ------------------
g++ -v : gcc version egcs-2.91.57 19980901
(egcs-1.1 release)
uname -sr : SunOS 5.6
//---------------------------------------------------------
//#########################################################
Actually, it does not: It points into the false direction, towards lots
of trouble. You should not fiddle with overloading 'operator<< ()' to
write to a special destination. In the context of streams, this operator
is overloaded to format user defined types. To write to a special
destination like eg. simultaneously to two streams a new stream buffer
is created. See my other answer in this thread for details.
--
<mailto:dietma...@claas-solutions.de>
homepage: <http://www.informatik.uni-konstanz.de/~kuehl>
Alex Vinokur wrote:
>
> In article <19991012134236...@ng-fz1.aol.com>,
> dremt...@aol.com (DREMTIME98) wrote:
> [snip]
> >
> > Now to my question. I wonder how I might be able to direct cout to
> not only
> > print to the screen but also write to a file. How do you use
> redirection for
> > that?
> >
> > Thanks a lot
> > Jim.
> >
> >******/* Could you please make comments here concerning what this is actually doing. Is it saying when OutFile is not open?*/
>
> Hi,
>
> See below.
> Hope this helps.
>
> Alex
>
> //#########################################################
> // File#1 of 3 : echo_file.H
> //------------------- C++ code : BEGIN -------------------
>
> //###########
> // echo_file.H
> //###########
>
> #ifndef echo_file_H
> #define echo_file_H
>
> #include <string>
> #include <iostream.h>
> #include <fstream.h>
> #include <assert.h>
>
> #define DEFAULT_OutFileName "Default.out"
>
> class echo_file
> {
>
> private:
> ofstream OutFile;
>
> public:
> echo_file ()
> {
> assert (!OutFile.is_open ());
******/* Could you please make comments here concerning what this is
actually doing. Is it saying when OutFile is not open?*/
> OutFile.open(DEFAULT_OutFileName);
> if (!OutFile.is_open ())
> {
> cout << "Cannot open "
> << DEFAULT_OutFileName
> << endl;
> exit (1);
> }
> }
>
> void setFileName (char const * const fn) // Is this * supposed to be a // pointer?????//
> This is awesome but could you answer my 2 questions? Scan below.
> Thanks, Will
>
[snip]
> > //#########################################################
> > // File#1 of 3 : echo_file.H
> > //------------------- C++ code : BEGIN -------------------
> >
> > //###########
> > // echo_file.H
> > //###########
> >
> > #ifndef echo_file_H
> > #define echo_file_H
> >
> > #include <string>
> > #include <iostream.h>
> > #include <fstream.h>
> > #include <assert.h>
> >
> > #define DEFAULT_OutFileName "Default.out"
> >
> > class echo_file
> > {
> >
> > private:
> > ofstream OutFile;
> >
> > public:
> > echo_file ()
> > {
//===============================================
// For instance, if we add the following line
OutFile.open(DEFAULT_OutFileName);
// (i.e. we create erroneous situation in the program,
// because we open this file below),
//===============================================
> > assert (!OutFile.is_open ()); // Line#31
> ******/* Could you please make comments here concerning what this is
> actually doing. Is it saying when OutFile is not open?*/
>
//===============================================
// we will get the following result of the running
// echo_file.H:31: failed assertion `!OutFile.is_open ()'
// Abort (core dumped)
// If OutFile is not open, the assert command is silent.
//===============================================
> > OutFile.open(DEFAULT_OutFileName);
> > if (!OutFile.is_open ())
> > {
> > cout << "Cannot open "
> > << DEFAULT_OutFileName
> > << endl;
> > exit (1);
> > }
> > }
> >
> > void setFileName (char const * const fn) // Is
this * supposed to be a // pointer?????//
//===============================================
// * is pointer.
// Concerning char const * const // see the thread titled "const char*
const" // ------------------ // in comp.lang.c++ // started 1999/02/08
//
http://www.deja.com/=dnc/[ST_rn=ps]/viewthread.xp?search=thread&recnum=%3c79m
ice$oid$1...@nnrp1.dejanews.com%3e%231/1&AN=441840331&svcclass=dnserver&frpage=g
etdoc.xp // ------------------ // in comp.lang.c++.moderated // started
1999/02/08 //
http://www.deja.com/=dnc/[ST_rn=ps]/viewthread.xp?search=thread&recnum=%3c79m
61o$ema$1...@nnrp1.dejanews.com%3e%231/1&AN=442245779&svcclass=dnserver&frpage=g
etdoc.xp //===============================================
> > {
> > OutFile.close ();
> > assert (!OutFile.is_open ());
> > OutFile.open(fn);
> > if (!OutFile.is_open ())
> > {
> > cout << "Cannot open "
> > << fn
> > << endl;
> > exit (1);
> > }
> > };
[snip]
Alex