using iostream library how do I display output to console as well as write to a file.

Discussion in 'C++' started by radnoraj, Apr 27, 2005.

  1. radnoraj

    radnoraj Guest

    Hi,
    I am sucessfull in redirecting console output to a file. but in this
    case nothing is displayed on the console, cout output is written to
    file without display.
    how do write the output to console as well as to file, my code is as
    below,
    =======================================================================
    #include <iostream.h>
    #include<ostream>
    #include<sstream>
    #include<iomanip>
    #include <fstream.h>
    #include <stdlib.h>

    int main(int argc, char* argv[])
    {
    ofstream outClientFile;
    streambuf *psbuf;
    char * s1 = " 00010 00000036 1 440 430 F 11
    007401F04077555098C57C0122000200E0 ";

    outClientFile.open("Clients.dat", ios::eek:ut);
    if(!outClientFile)
    {
    cerr << "File could not be Opened"<<endl;
    exit(1);
    }
    cout << "You will not see any screen Output" << endl
    << "Console Output is redirected to a File"<< endl << "... \n";
    psbuf = outClientFile.rdbuf();
    cout.rdbuf(psbuf);
    for(int i=0; i< 10; i++)
    {
    cout << s1<<endl;
    cout.flush();
    }
    outClientFile.close();
    return 0;
    }
    =====================================================================
    Any Idea pls. discuss..

    Thanks
     
    radnoraj, Apr 27, 2005
    #1
    1. Advertising

  2. radnoraj

    red floyd Guest

    Re: using iostream library how do I display output to console aswell as write to a file.

    radnoraj wrote:
    > Hi,
    > I am sucessfull in redirecting console output to a file. but in this
    > case nothing is displayed on the console, cout output is written to
    > file without display.
    > how do write the output to console as well as to file, my code is as
    > below,


    You need to write a custom streambuf that will write to two places at once.

    > =======================================================================
    > #include <iostream.h>

    don't use this, use <iostream>
    > #include<ostream>
    > #include<sstream>

    you don't need <sstream>, you never use an stringstream
    > #include<iomanip>
    > #include <fstream.h>

    dont use this, use <fstream>
    > #include <stdlib.h>

    You should use <cstdlib> instead, but this is not an error.

    [redacted]
     
    red floyd, Apr 28, 2005
    #2
    1. Advertising

  3. radnoraj

    David White Guest

    "radnoraj" <> wrote in message
    news:...
    > Hi,
    > I am sucessfull in redirecting console output to a file. but in this
    > case nothing is displayed on the console, cout output is written to
    > file without display.
    > how do write the output to console as well as to file, my code is as
    > below,
    > =======================================================================
    > #include <iostream.h>
    > #include<ostream>
    > #include<sstream>
    > #include<iomanip>
    > #include <fstream.h>
    > #include <stdlib.h>
    >
    > int main(int argc, char* argv[])
    > {
    > ofstream outClientFile;
    > streambuf *psbuf;
    > char * s1 = " 00010 00000036 1 440 430 F 11
    > 007401F04077555098C57C0122000200E0 ";
    >
    > outClientFile.open("Clients.dat", ios::eek:ut);
    > if(!outClientFile)
    > {
    > cerr << "File could not be Opened"<<endl;
    > exit(1);
    > }
    > cout << "You will not see any screen Output" << endl
    > << "Console Output is redirected to a File"<< endl << "... \n";
    > psbuf = outClientFile.rdbuf();
    > cout.rdbuf(psbuf);
    > for(int i=0; i< 10; i++)
    > {
    > cout << s1<<endl;
    > cout.flush();
    > }
    > outClientFile.close();
    > return 0;
    > }
    > =====================================================================
    > Any Idea pls. discuss..


    I needed to do this myself recently and used my own multi-ostream. It only
    supports << operations, but that's all I needed. Example program:

    #include <ostream>
    #include <iostream>
    #include <fstream>
    #include <iomanip>

    class MultiOstream
    {
    public:
    MultiOstream(std::eek:stream &os1, std::eek:stream &os2)
    : m_os1(os1), m_os2(os2) {}
    template<typename T> MultiOstream &operator<<(const T &v)
    {
    m_os1 << v;
    m_os2 << v;
    return *this;
    }
    MultiOstream &operator<<(std::eek:stream &(*f)(std::eek:stream&))
    {
    m_os1 << f;
    m_os2 << f;
    return *this;
    }

    private:
    std::eek:stream &m_os1;
    std::eek:stream &m_os2;
    };

    int main()
    {
    std::eek:fstream ofs("File.out");
    MultiOstream mos(std::cout, ofs);
    mos << std::setw(20) << "Hello world" << std::endl;
    }

    The second << function had to be a template specialization with VC++ 6.0,
    but VC++ 7.0 didn't like that and only accepted a non-template function. I
    don't know if there's a way to avoid that special case altogether.

    DW
     
    David White, Apr 28, 2005
    #3
  4. radnoraj

    Guest

    Re: using iostream library how do I display output to console as well as write to a file.

    Radnoraj,

    I also needed this kind of functionality, so I wrote a framework which
    allows you to register any number of streams, then use a `dispatcher'
    stream which wil write any output to all of the streams which you
    registered.

    The basic idea is as follows:
    1. Have a singleton registry object (LogRegistry), which holds pointers
    to the output streams
    2. Implement the dispatching mechanism by writing a LogBuffer class,
    derived from std::streambuf. The flush() function in this buffer gets
    all the registered streams from the LogRegistry object, and writes to
    each one in turn. (See Josuttis if you're not up on the internals of
    iostreams)
    3. The class which you actually use on the lhs of your << operators,
    LogStream, is simply a std::eek:stream whose internal buffer is an
    instance of LogBuffer.

    I added one extra feature which is that each registered stream is
    associated with a `logging level'. This is just a number which allows
    you to choose which stream(s) each message is sent to. In this way you
    can have a main log file to which all messages get sent, an error file
    which only receives warning messages, and an error file to which any
    serious errors are written. The user selects the appropriate level for
    any given message using stream manipulators.

    The following code, which should compile standalone, illustrates the
    idea - you should be able to hack this to suit your needs.

    HTH
    Gareth




    //----------------
    // Interface
    //-------------

    #include <streambuf>
    #include <ostream>
    #include <iomanip>
    #include <map>


    // A class with which users can register logging streams
    struct LogRegister {

    typedef std::multimap<unsigned, std::eek:stream*> log_map_t;
    log_map_t log_map;

    void register_stream(std::eek:stream& stream, unsigned pri);

    void write(const std::string& s, unsigned level) const;

    static LogRegister& instance();

    private:
    LogRegister();
    };


    // Forward declaration
    class LogStream;

    // Custom streambuf
    struct LogBuffer : public std::streambuf {

    LogBuffer(LogStream* s);
    ~LogBuffer();

    private:

    // The buffer holds a pointer to the stream, as it needs to query

    // the stream to obtain the current logging level
    LogStream* stream_ptr;
    std::string buffer;

    int_type overflow(int_type i);
    void flush();
    };


    // The actual stream class (the `message dispatcher')
    class LogStream : public std::eek:stream {

    LogBuffer buffer;

    public:

    // Index into the ios state array
    static const int level_index;

    LogStream();
    unsigned get_level();
    };


    // Manipulators allowing the user to specify logging levels
    struct LogLevelManipulator {

    unsigned value;
    LogLevelManipulator(unsigned v) : value(v) { }
    };

    // This is just a convenience function for creating level manipulators
    LogLevelManipulator log_level(unsigned n);

    // The function which modifies the stream's logging level according to
    // a manipulator object
    std::eek:stream& operator<<(std::eek:stream& out, LogLevelManipulator l);



    //--------------------
    // Implementation
    //------------------

    void LogRegister::register_stream(std::eek:stream& stream, unsigned pri)
    { log_map.insert(std::make_pair(pri, &stream)); }

    void LogRegister::write(const std::string& s, unsigned level) const {

    for(log_map_t::const_iterator i = log_map.lower_bound(level);
    i != log_map.end(); ++i)
    *(i->second) << s;
    }

    LogRegister& LogRegister::instance()
    { static LogRegister lr; return lr; }

    LogRegister::LogRegister()
    { }





    LogBuffer::LogBuffer(LogStream* s)
    : stream_ptr(s)
    { }


    LogBuffer::~LogBuffer()
    { flush(); }


    LogBuffer::int_type LogBuffer::eek:verflow(int_type i) {

    if(!traits_type::eq_int_type(i, traits_type::eof())) {

    char_type c = traits_type::to_char_type(i);
    buffer.push_back(c);
    if(c == '\n') flush();
    }

    return traits_type::not_eof(i);
    }


    void LogBuffer::flush() {

    LogRegister::instance().write(buffer, stream_ptr->get_level());
    buffer.clear();
    }


    // Stream class

    LogStream::LogStream()
    : std::eek:stream(&buffer), buffer(this)
    { }


    unsigned LogStream::get_level()
    { return iword(level_index); }


    const int LogStream::level_index = std::ios::xalloc();



    // Manipulators

    LogLevelManipulator log_level(unsigned n)
    { return LogLevelManipulator(n); }


    std::eek:stream& operator<<(std::eek:stream& out, LogLevelManipulator l) {

    // First flush the stream
    out << std::flush;

    // Now set the level
    out.iword(LogStream::level_index) = l.value;
    return out;
    }


    //----------------------
    // Example
    //--------------

    #include <fstream>
    #include <iostream>
    #include <stdexcept>

    int main() {

    std::eek:fstream log_stream("/tmp/test.log");
    std::eek:fstream error_stream("/tmp/test.err");

    // Register the streams. The higher the level, the more messages
    // that stream will receive. Here std::cout is reserved for only
    // the serious messages which the user needs to see right now.
    LogRegister::instance().register_stream(std::cout, 0);
    LogRegister::instance().register_stream(error_stream, 1);
    LogRegister::instance().register_stream(log_stream, 2);

    // This is the `dispatcher' object
    LogStream multi;

    // Define some level manipulators
    const LogLevelManipulator
    normal = log_level(2),
    error = log_level(1),
    fatal = log_level(0);

    try {

    // Set the initial logging level
    multi << normal;

    // Most program output just goes to the log; not printed to the
    // console
    multi << "Standard message; just sent to the 'log' stream"
    << std::endl;
    multi << "Another routine message" << std::endl;

    // Oops, an error occurred - this is logged to error_stream
    // but does not abort the program
    multi << error << "A nasty error occurred..." << std::endl
    << normal;
    // Note that the log level has been reset to `normal'

    // ... and back to routine logging
    multi << "Back to normal" << std::endl;

    // Now something nasty happens, resulting in an uncaught
    // exception propagating to the top level. This will abort the
    // program.
    throw std::runtime_error("Blah blah");
    }
    catch(std::exception& e) {

    multi << fatal << "A catastrophic error occurred:" << std::endl
    << e.what() << std::endl
    << "Aborting..." << std::endl;
    log_stream.close();
    error_stream.close();
    exit(1);
    }
    }
     
    , Apr 28, 2005
    #4
  5. "radnoraj" <> wrote in message
    news:...
    | Hi,
    | I am sucessfull in redirecting console output to a file. but in this
    | case nothing is displayed on the console, cout output is written to
    | file without display.
    | how do write the output to console as well as to file, my code is as
    | below,
    | =======================================================================
    | #include <iostream.h>
    | #include<ostream>
    | #include<sstream>
    | #include<iomanip>
    | #include <fstream.h>
    | #include <stdlib.h>
    |
    | int main(int argc, char* argv[])
    | {
    | ofstream outClientFile;
    | streambuf *psbuf;
    | char * s1 = " 00010 00000036 1 440 430 F 11
    | 007401F04077555098C57C0122000200E0 ";
    |
    | outClientFile.open("Clients.dat", ios::eek:ut);
    | if(!outClientFile)
    | {
    | cerr << "File could not be Opened"<<endl;
    | exit(1);
    | }
    | cout << "You will not see any screen Output" << endl
    | << "Console Output is redirected to a File"<< endl << "... \n";
    | psbuf = outClientFile.rdbuf();
    | cout.rdbuf(psbuf);
    | for(int i=0; i< 10; i++)
    | {
    | cout << s1<<endl;
    | cout.flush();
    | }
    | outClientFile.close();
    | return 0;
    | }
    | =====================================================================
    | Any Idea pls. discuss..

    You can take advantage of the fact that an 'ifstream' *is* an
    'ostream':

    inline void Print( std::eek:stream& Stream, const char* Source )
    {
    Stream << Source;
    }

    inline void LogToStreams( std::eek:stream& ToFile,
    std::eek:stream& ToScreen, const char* Source )
    {
    Print( ToFile, Source );
    Print( ToScreen, Source );
    }

    int main()
    {
    std::eek:fstream ofs( "System.Log.txt" );
    LogToStreams( ofs, std::cout, "Some source string\n" );

    return 0;
    }

    This just uses a helper function called 'Print', but it's
    pretty straight forward.

    *NOTE* There is no error checking provided to keep the
    example clear and to the point.

    Btw, what's wrong with utilising the 'std::cerr' object
    in conjunction with the 'std::cout' object ?

    You could just redirect one of them, and use the other
    as per normal ?

    Cheers,
    Chris Val
     
    Chris \( Val \), Apr 28, 2005
    #5
  6. radnoraj

    Samee Zahur Guest

    Re: using iostream library how do I display output to console as well as write to a file.

    Well, I'm not sure about this, but I don't think cerr and cout even
    needs to be the same physical device by default. Using cerr leaves the
    *user* with no neat way of suppressing the output (even though the
    programmer might want it displayed). Plus, it hinders piping and other
    neat things we do with cout - the point is cerr is just not meant to be
    used for normal outputs, it is there for error messages only (which is
    less likely to need supressions).

    And I think there's been a typo here - I'm sure you mean 'ofstream':
    > You can take advantage of the fact that an 'ifstream' *is* an
    > 'ostream':


    Samee
     
    Samee Zahur, Apr 30, 2005
    #6
  7. Re: using iostream library how do I display output to console as well as write to a file.

    "Samee Zahur" <> wrote in message
    news:...
    | Well, I'm not sure about this, but I don't think cerr and cout even
    | needs to be the same physical device by default.

    Well, I'm not sure what you're not sure about ? :)

    | Using cerr leaves the *user* with no neat way of suppressing the
    | output (even though the programmer might want it displayed).

    I don't follow you, I'm sorry.
    The first line seems to contradict the last?

    | Plus, it hinders piping and other neat things we do with cout -
    | the point is cerr is just not meant to be used for normal outputs,
    | it is there for error messages only (which is less likely to need
    | supressions).

    I'm still not sure what you're getting at, but just let me clarify,
    that what I was alluding to was to redirect the std::cerr object to
    write to file, and use the std::cout object to continue writing to
    the console.

    | And I think there's been a typo here - I'm sure you mean 'ofstream':
    | > You can take advantage of the fact that an 'ifstream' *is* an
    | > 'ostream':

    Ah - Good catch :)
    Yes, I did indeed mean to write an 'std::eek:fstream' object.

    Cheers,
    Chris Val
     
    Chris \( Val \), Apr 30, 2005
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Tiger
    Replies:
    10
    Views:
    5,631
  2. ai@work
    Replies:
    9
    Views:
    556
    Ron Natalie
    Dec 16, 2004
  3. S. Nurbe

    iostream + iostream.h

    S. Nurbe, Jan 14, 2005, in forum: C++
    Replies:
    7
    Views:
    786
    red floyd
    Jan 15, 2005
  4. red floyd
    Replies:
    3
    Views:
    544
    Dietmar Kuehl
    Mar 8, 2005
  5. Replies:
    5
    Views:
    3,445
    James Kanze
    Mar 4, 2008
Loading...

Share This Page