views:

93

answers:

4

Hi All, I'm working on a file sharing application in C++. I want to write console output into a separate file and at the same time I want to see the output in console also. Can anybody help me...Thanks in advance.

A: 

i don't program in c++ but here is my advice: create new class, that takes InputStream (istream in c++ or smth), and than every incoming byte it will transfer in std.out and in file.
I am sure there is a way to change standard output stream with forementioned class. As i remember, std.out is some kind of property of cout.
And again, i spent 1 week on c++ more than half a year ago, so there is a chance that all i've said is garbage.

foret
+1  A: 

Here we go...

#include <fstream>
    using std::ofstream;
#include <iostream>
    using std::cout;
    using std::endl;

int main( int argc, char* argv[] )
{
    ofstream file( "output.txt" ); // create output file stream to file output.txt
    if( !file ) // check stream for error (check if it opened the file correctly)
        cout << "error opening file for writing." << endl;

    for( int i=0; i<argc; ++i ) // argc contains the number of arguments
    {
        file << argv[i] << endl; // argv contains the char arrays of commandline arguments
        cout << argv[i] << endl;
    }
    file.close(); // always close a file stream when you're done with it.

    return 0;
}

PS: OK, read your question wrong (console output/input mixup), but you still get the idea I think.

rubenvb
`i < argc` will suffice (since count gives the number of elements in a zero-based array). `i <= argc` will overrun the bounds of the array.
Johnsyweb
@Johnsywen: thanks, corrected.
rubenvb
+1  A: 

The idea is to create a derivate of std::streambuf which will output data to both the file and cout. Then create an instance of it and use cout.rdbuf(...);

Here is the code (tested with MSVC++ 2010, should work on any compiler):

class StreambufDoubler : public std::streambuf {
public:
    StreambufDoubler(std::streambuf* buf1, std::streambuf* buf2) :
            _buf1(buf1), _buf2(buf2), _buffer(128)
    {
        assert(_buf1 && _buf2);

        setg(0, 0, 0);
        setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());
    }

    ~StreambufDoubler() {
        sync();
    }

    void imbue(const std::locale& loc) {
        _buf1->pubimbue(loc);
        _buf2->pubimbue(loc);
    }

    std::streampos seekpos(std::streampos sp, std::ios_base::openmode which) {
        return seekoff(sp, std::ios_base::cur, which);
    }

    std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which) {
        if (which | std::ios_base::in)
            throw(std::runtime_error("Can't use this class to read data"));

        // which one to return? good question
        // anyway seekpos and seekoff should never be called
        _buf1->pubseekoff(off, way, which);
        return _buf2->pubseekoff(off, way, which);
    }

    int overflow(int c) {
        int retValue = sync() ? EOF : 0;
        sputc(c);
        return retValue;
    }

    int sync() {
        _buf1->sputn(pbase(), pptr() - pbase());
        _buf2->sputn(pbase(), pptr() - pbase());
        setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());
        return _buf1->pubsync() | _buf2->pubsync();
    }

private:
    std::streambuf*     _buf1;
    std::streambuf*     _buf2;

    std::vector<char>   _buffer;
};


int main() {
    std::ofstream myFile("file.txt");
    StreambufDoubler doubler(std::cout.rdbuf(), myFile.rdbuf());
    std::cout.rdbuf(&doubler);

    // your code here

    return 0;
}

However note that a better implementation would use templates, a list of streambufs instead of just two, etc. but I wanted to keep it as simple as possible.

Tomaka17
Thanks Tomaka,is it possible to catch only exception error messages in log file? Here, its(cpp) client application.Now I want to show server-client connection establishment details in console and whatever exceptions come in file transfer like memory exception,...etc want to be written in log file.
Kishor Kumar
If you're talking about C++ exceptions you have to catch them manually anyway, so you can redirect them to either a file or cerr instead of cout. But I'm not sure I really understood your question
Tomaka17
Thanks Tomkat, Now I can print whatever data I want in console using cerr.
Kishor Kumar
+1  A: 

What you want actually is to follow in real time the lines added to the log your application writes.

In the Unix world, there's a simple tool that has that very function, it's called tail.

Call tail -f your_file and you will see the file contents appearing in almost real time in the console.

Unfortunately, tail is not a standard tool in Windows (which I suppose you're using, according to your question's tags). It can however be found in the GnuWin32 package, as well as MSYS.

There are also several native tools for Windows with the same functionality, I'm personally using Tail For Win32, which is licensed under the GPL.

So, to conclude, I think your program should not output the same data to different streams, as it might slow it down without real benefits, while there are established tools that have been designed specifically to solve that problem, without the need to develop anything.

SirDarius
+1 If the interpretation is correct, which I think, `tail` is the way to go
Gianluca