How to redirect cin and cout to files?
Asked Answered
F

8

189

How can I redirect cin to in.txt and cout to out.txt?

Fornax answered 14/4, 2012 at 2:19 Comment(1)
Redirect cin to a string : https://mcmap.net/q/137003/-redirect-cin-to-a-string - Redirect cout to a string : #1162568Shu
T
279

Here is an working example of what you want to do. Read the comments to know what each line in the code does. I've tested it on my pc with gcc 4.6.1; it works fine.

#include <iostream>
#include <fstream>
#include <string>

void f()
{
    std::string line;
    while(std::getline(std::cin, line))  //input from the file in.txt
    {
        std::cout << line << "\n";   //output to the file out.txt
    }
}
int main()
{
    std::ifstream in("in.txt");
    std::streambuf *cinbuf = std::cin.rdbuf(); //save old buf
    std::cin.rdbuf(in.rdbuf()); //redirect std::cin to in.txt!
    
    std::ofstream out("out.txt");
    std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
    std::cout.rdbuf(out.rdbuf()); //redirect std::cout to out.txt!

    std::string word;
    std::cin >> word;           //input from the file in.txt
    std::cout << word << "  ";  //output to the file out.txt
    
    f(); //call function


    std::cin.rdbuf(cinbuf);   //reset to standard input again
    std::cout.rdbuf(coutbuf); //reset to standard output again

    std::cin >> word;   //input from the standard input
    std::cout << word;  //output to the standard input
}

You could save and redirect in just one line as:

auto cinbuf = std::cin.rdbuf(in.rdbuf()); //save and redirect

Here std::cin.rdbuf(in.rdbuf()) sets std::cin's buffer to in.rdbuf() and then returns the old buffer associated with std::cin. The very same can be done with std::cout — or any stream for that matter.

Tramway answered 14/4, 2012 at 5:30 Comment(8)
Do I need to close the files before I reset cin and cout to standard IO?Fornax
@updogliu: No. If you want, you can use in and out to read from and write to, in.txt and out.txt respectively. Also, the files will be closed automatically when in and out go out of scope.Tramway
I like this solution over the freopen one because I can no longer get my stdout back if I use freopen. #26700024Schneider
What if I don't want to keep the old buf from cin or cout around? Should I delete them?Margarine
I tried this solution but i got: **** stack smashing detected *** Is it an expected result in certain cases?Fleecy
@YanivG: What else are you doing apart from what this solution suggests? I'm sure you're doing more stuffs that I did here. Could you post a minimal code that reproduces the error, a screen of the error you're getting. Create gist on Github and share the link here.Tramway
@Nawaz: Thanks, indeed it was my fault. However, I realized that all printouts from the very same thread, where I executed the "cout redirection" go to a file. But all "cout" from another threads, do not go to the file, but they are still silenced and don't show on screen. I wished that redirecting "cout" will effect all running thread. Is this even possible?Fleecy
It should affect all threads. Maybe something is still missing in your code. BTW, did you try doing the redirect-setup BEFORE creating other threads? Try that and see if that works.Tramway
G
111

Just write

#include <cstdio>
#include <iostream>
using namespace std;

int main()
{
    freopen("output.txt","w",stdout);
    cout<<"write in file";
    return 0;
}
Gisborne answered 15/12, 2012 at 0:46 Comment(8)
This will redirect printf too, which in some cases may be a good thing.Seow
@Fornax as far as my knowledge goes, stdout and cout are in sync all the timeTimbered
@AkshayLAradhya Not when you set std::sync_with_studio(false);, although by default it is set to true.Conjunction
@reggaeguitar This is a little bit ugly solution. You should use std for iostream not stdio.Eventide
@PřemyslŠťastný why?Kindrakindred
@Kindrakindred The C++ standard doesn't require the iostream library to use stdio, so this is not portable. The only reason this answer appears simpler is because the original answer provides more information, and an example of setting and preserving it.Forenamed
If the answers were equal in functionality, the C++ equivalent of this would be ofstream out("out.txt"); cout.rdbuf(out.rdbuf()); - only one extra line, and it's portable. Not soooo much simpler :)Forenamed
@Forenamed Fair enough, you're right. I guess it depends on whether you need it to be portable or not. The reason I was looking this up was for testing coding challenge problems so I just wanted a quick and easy answer. Obviously that's a very different need than someone writing production code.Kindrakindred
R
31

Here is a short code snippet for shadowing cin/cout useful for programming contests:

#include <bits/stdc++.h>

using namespace std;

int main() {
    ifstream cin("input.txt");
    ofstream cout("output.txt");

    int a, b;   
    cin >> a >> b;
    cout << a + b << endl;
}

This gives additional benefit that plain fstreams are faster than synced stdio streams. But this works only for the scope of single function.

Global cin/cout redirect can be written as:

#include <bits/stdc++.h>

using namespace std;

void func() {
    int a, b;
    std::cin >> a >> b;
    std::cout << a + b << endl;
}

int main() {
    ifstream cin("input.txt");
    ofstream cout("output.txt");

    // optional performance optimizations    
    ios_base::sync_with_stdio(false);
    std::cin.tie(0);

    std::cin.rdbuf(cin.rdbuf());
    std::cout.rdbuf(cout.rdbuf());

    func();
}

Note that ios_base::sync_with_stdio also resets std::cin.rdbuf. So the order matters.

See also Significance of ios_base::sync_with_stdio(false); cin.tie(NULL);

Std io streams can also be easily shadowed for the scope of single file, which is useful for competitive programming:

#include <bits/stdc++.h>

using std::endl;

std::ifstream cin("input.txt");
std::ofstream cout("output.txt");

int a, b;

void read() {
    cin >> a >> b;
}

void write() {
    cout << a + b << endl;
}

int main() {
    read();
    write();
}

But in this case we have to pick std declarations one by one and avoid using namespace std; as it would give ambiguity error:

error: reference to 'cin' is ambiguous
     cin >> a >> b;
     ^
note: candidates are: 
std::ifstream cin
    ifstream cin("input.txt");
             ^
    In file test.cpp
std::istream std::cin
    extern istream cin;  /// Linked to standard input
                   ^

See also How do you properly use namespaces in C++?, Why is "using namespace std" considered bad practice? and How to resolve a name collision between a C++ namespace and a global function?

Rosiarosicrucian answered 21/7, 2016 at 12:56 Comment(0)
L
14

assuming your compiles prog name is x.exe and $ is the system shell or prompt

$ x <infile >outfile 

will take input from infile and will output to outfile .

Lur answered 21/9, 2014 at 20:33 Comment(1)
That is not C++ related and fails in any non-trivial example, for example when your program spawns child processes that write to the console. At least that's the problem I've encountered when I tried such redirection, hence why I'm here.Maxson
U
10

Try this to redirect cout to file.

#include <iostream>
#include <fstream>

int main()
{
    /** backup cout buffer and redirect to out.txt **/
    std::ofstream out("out.txt");

    auto *coutbuf = std::cout.rdbuf();
    std::cout.rdbuf(out.rdbuf());

    std::cout << "This will be redirected to file out.txt" << std::endl;

    /** reset cout buffer **/
    std::cout.rdbuf(coutbuf);

    std::cout << "This will be printed on console" << std::endl;

    return 0;
}

Read full article Use std::rdbuf to Redirect cin and cout

Understrapper answered 1/6, 2018 at 19:35 Comment(8)
The question had been answered almost 6 years back (in 2012), yet you've added an answer now in 2018. Your answer is same as the accepted answer. So I'm wondering why did you post this when you didn't have anything new to add?Tramway
My answer highlight only cout version specially and the detailed answer is provided in the link below.Understrapper
What is new in your answer which is not present in the accepted answer?Tramway
My answer doesn’t mix redirection of both cout and cin , my version separates to make it more readableUnderstrapper
@HaseeBMir But the question was how to redirect cin AND cout. And sorry, most programmers will be able to strip that half of the accepted answer, that they don't need, if they redirect only cin or only cout.Margarine
This answer added the new piece of info for how to reset cout to the normal situation. Very useful, very readable, and includes a reference link. Thanks Haseeb. +1Meiny
I had: error: variable ‘std::ofstream out’ has initializer but incomplete type 53 | std::ofstream out("logs.txt"); and error: ‘cout’ in namespace ‘std’ does not name a type 55 | std::cout.rdbuf(out.rdbuf());Cainozoic
@JAgustinBarrachina it seems like the problem here is with the headers. Just make sure you've included <fstream> at the top of your code for std::ofstream. This should i guess fix 1st error. And for std::cout, well, that's with <iostream>Understrapper
C
2

If your input file is in.txt, you can use freopen to set stdin file as in.txt

freopen("in.txt","r",stdin);

if you want to do the same with your output:

freopen("out.txt","w",stdout);

this will work for std::cin (if using c++), printf, etc...

This will also help you in debugging your code in clion, vscode

Edit
If you want to reset stdin

fclose(stdin);
stdin = fdopen(0, "r"); //reopen: 0 is file descriptor of std input

and to reset stdout

fclose(stdout);
stdout = fdopen(1, "w"); //reopen: 1 is file descriptor of std output
Confidence answered 20/1, 2021 at 8:31 Comment(3)
How do you reset stdout in that case?Terrain
@Broxigar Edited to add info about resettingConfidence
When trying to use "freopen("out.txt","w",stdout);" for the stdout, but then trying to use a regular "cin" to get input from user, i get a segmentation fault. any idea?Fleecy
S
1

I/O Redirection in C++

https://www.geeksforgeeks.org/io-redirection-c/

// Cpp program to redirect cout to a file
#include <fstream>
#include <iostream>
#include <string>
 
using namespace std;
 
int main()
{
    fstream file;
    file.open("cout.txt", ios::out);
    string line;
 
    // Backup streambuffers of  cout
    streambuf* stream_buffer_cout = cout.rdbuf();
    streambuf* stream_buffer_cin = cin.rdbuf();
 
    // Get the streambuffer of the file
    streambuf* stream_buffer_file = file.rdbuf();
 
    // Redirect cout to file
    cout.rdbuf(stream_buffer_file);
 
    cout << "This line written to file" << endl;
 
    // Redirect cout back to screen
    cout.rdbuf(stream_buffer_cout);
    cout << "This line is written to screen" << endl;
 
    file.close();
    return 0;
}
Slot answered 31/5, 2021 at 8:16 Comment(1)
Hello and welcome to Stackoverflow. You have answered a very old question with many answers. Please edit your question and add an explanation why this answer is better than the othersKendallkendell
B
1

The accepted answer shows the right way to redirect cin and cout. You need to construct another stream object whose life time exceeds that of cin or cout. If you want to write a function works like freopen, you can alloc an array for each stream to be redirected, to save the allocated stream objects.

#include <iostream>
#include <string>
#include <fstream>
#include <vector>

using namespace std;

template<typename>
    struct fstream_traits { };
template<typename CharT, typename Traits>
    struct fstream_traits<basic_istream<CharT, Traits>> { using type = basic_ifstream<CharT, Traits>; };
template<typename CharT, typename Traits>
    struct fstream_traits<basic_ostream<CharT, Traits>> { using type = basic_ofstream<CharT, Traits>; };

template <typename Stream>
void redirect(Stream& str, string filename)
{
    using fstream_type = typename fstream_traits<Stream>::type;
    static int index = std::ios_base::xalloc();
    if (str.pword(index) == nullptr)
    {
        str.pword(index)= new vector<ios_base*>{};
        str.register_callback([](ios_base::event event, std::ios_base& stream, int index) {
            if (event == ios_base::erase_event)
            {
                for (auto fs : *(vector<ios_base*>*)stream.pword(index))
                    delete fs;
                delete (vector<ios_base*>*)stream.pword(index);
            }
        }, index);
    }
    vector<ios_base*>* list = (vector<ios_base*>*)str.pword(index);
    list->push_back(new fstream_type{filename});
    str.rdbuf(dynamic_cast<fstream_type*>(list->back())->rdbuf())->~basic_streambuf();
}

int main()
{
    redirect(cout, "out.txt");
    cout << "Redirected text!";
    return 0;
}

The template and alias are not required if you explicitly use istream/ostream instead of Stream.

Bekki answered 11/2, 2022 at 18:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.