如何将cin和cout重定向到文件?

188
我该如何将 cin 重定向到 in.txt,并将 cout 重定向到 out.txt

8
将 cin 重定向到一个字符串:https://dev59.com/E2445IYBdhLWcg3wUYrM将 cout 重定向到一个字符串:https://dev59.com/TnM_5IYBdhLWcg3w8IA2 - Dr.Kameleon
8个回答

277

这是一个可行的示例,可以完成你想做的事情。阅读注释以了解代码中每行的作用。我已在我的pc上使用gcc 4.6.1进行了测试;它能正常工作。

#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
}

您可以使用以下一行代码完成保存并重定向:

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

这里std::cin.rdbuf(in.rdbuf())std::cin的缓冲区设置为in.rdbuf()并返回与std::cin关联的旧缓冲区。同样的操作也可以用于std::cout或者任何其他


5
重置 cin 和 cout 到标准 IO 前,我需要先关闭文件吗? - updogliu
4
不。如果需要的话,你可以使用 inout 来分别读取和写入文件,分别对应于 in.txtout.txt。此外,当 inout 超出作用域范围时,文件将自动关闭。 - Nawaz
1
我喜欢这个解决方案,而不是使用freopen,因为如果我使用freopen,我将无法再次获取我的stdout。https://stackoverflow.com/questions/26699524/how-to-write-in-stdout-after-using-freopen - xxks-kkk
如果我不想保留来自cin或cout的旧缓冲区怎么办?我应该使用“delete”吗? - Kai Petzke
我尝试了这个解决方案,但是出现了以下错误: **** stack smashing detected ***在某些情况下,这是预期的结果吗? - Yaniv G
显示剩余3条评论

111

只需写作

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

int main()
{
    freopen("output.txt","w",stdout);
    cout<<"write in file";
    return 0;
}

6
这也会将printf重定向,有些情况下这可能是一件好事。 - JDiMatteo
7
@AkshayLAradhya 当你设置std::sync_with_studio(false);时,就不会有这个问题了,尽管默认情况下它是设置为true的。 - vsoftco
2
@PřemyslŠťastný 为什么? - reggaeguitar
4
如果这些答案在功能上是相等的,那么C++版本的等价代码应该是 ofstream out("out.txt"); cout.rdbuf(out.rdbuf()); - 只多了一行代码,而且它是可移植的。虽然不会简单太多 :) - nevelis
2
@nevelis 说得对,很公正。我猜这取决于你是否需要它具有可移植性。我查找这个的原因是为了测试编码挑战问题,所以我只想要一个快速简单的答案。显然,这与编写生产代码的人有非常不同的需求。 - reggaeguitar
显示剩余3条评论

31

这是一个有用的编程竞赛 cin/cout 输入输出重定向的简短代码示例:

#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;
}

这样做的额外好处是普通的 fstream 比同步的 stdio 流更快。但是这仅适用于单个函数的范围。

全局 cin/cout 重定向可以写成:

#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();
}

请注意,ios_base::sync_with_stdio还会重置std::cin.rdbuf。因此顺序很重要。

另请参阅《ios_base::sync_with_stdio(false); cin.tie(NULL);的意义》

对于单个文件的范围,标准输入输出流也可以很容易地被遮蔽,这在竞赛编程中很有用:

#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();
}

但在这种情况下,我们必须逐个选择 std 声明,并避免使用 using namespace std;,因为它会导致歧义错误:

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
                   ^

另请参见如何正确使用C++命名空间?为什么被认为“using namespace std”是不良实践?以及如何解决C++命名空间和全局函数之间的名称冲突?


14

假设您编译的程序名为x.exe,$表示系统shell或提示符

$ x <infile >outfile 

将从输入文件中获取输入,并输出到输出文件中。


2
这与C++无关,并且在任何非平凡的示例中都会失败,例如当您的程序生成写入控制台的子进程时。至少这是我尝试进行此类重定向时遇到的问题,因此我来到这里。 - ashrasmun

10

尝试以下方法将cout重定向到文件。

#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;
}

阅读完整文章:使用std::rdbuf重定向cin和cout


4
这个问题已经在6年前(2012年)得到了回答,然而你在2018年又添加了一个回答。你的回答与被接受的回答相同。所以我在想,既然你没有任何新的东西要补充,为什么还要发布这个回答呢? - Nawaz
1
我的回答只特别强调了cout版本,详细的答案在下面的链接中提供。 - Haseeb Mir
3
你的问题是:“在你的回答中,有什么是在被接受的回答中没有的新内容?”,我的翻译如下:“你的回答有哪些新的内容是被接受的回答中没有的?”请注意,我的翻译尽可能保持了原文的意思和结构,同时使语言更为通俗易懂。 - Nawaz
4
我的答案不混合使用cout和cin的重定向,我的版本将它们分开以使其更易读。 - Haseeb Mir
@HaseeBMir 但问题是如何重定向 cincout。抱歉,如果只重定向 cin 或只重定向 cout,大多数程序员都能剥离掉那个他们不需要的答案的一半。 - Kai Petzke
1
这个答案增加了如何将cout重置为正常状态的新信息。非常有用,易于阅读,并包含参考链接。谢谢Haseeb。+1 - Roland

2
如果您的输入文件为in.txt,则可以使用freopen将标准输入文件设置为in.txt。
freopen("in.txt","r",stdin);

如果你想用相同的方式处理你的输出:
freopen("out.txt","w",stdout);

这将适用于 std::cin(如果使用 c++),printf 等...

这也将帮助您在 clion、vscode 中调试代码

编辑
如果您想重置 stdin

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

并重置标准输出

fclose(stdout);
stdout = fdopen(1, "w"); //reopen: 1 is file descriptor of std output

在这种情况下,您如何重置stdout - ex1led
@Broxigar 编辑后添加有关重置信息的内容 - Vishal Singh
尝试使用“freopen("out.txt","w",stdout);”将 stdout 用于输出,但接下来尝试使用常规的“cin”从用户获取输入时,我遇到了分段错误。有任何想法吗? - Yaniv G

1

接受的答案展示了正确的重定向 cincout 的方式。您需要构造另一个流对象,其生命周期超过 cincout。如果您想编写一个类似于 freopen 的函数,则可以为每个要重定向的流分配一个数组,以保存已分配的流对象。

#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;
}

如果您明确使用istream/ostream而不是Stream,则模板和别名不是必需的。

1

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;
}

1
你好,欢迎来到Stackoverflow。你回答了一个非常古老的问题,而且已经有很多答案了。请编辑你的回答,并解释为什么这个答案比其他答案更好。 - Michael Kotzjan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接