Cracking C++(5):cout打印到文件

1. 目的

用 cout 打印到屏幕很简单, 用 ostream 打印到文件也很简单。
但, 如果一个代码中有多处 cout, 又不想一个一个改成 ostream 对象, 怎样做呢?
如果一部分 cout 希望打印到文件, 另一部分 cout 希望打印到控制台, 又该怎么做呢?

2. cout 输出到控制台

#include <iostream>
#include <string>
#include <chrono>
#include <ctime>

int main()
{
    using namespace std;

    cout << "hello world\n";
    cout << "学习·现代·西佳佳\n";
    cout << "__cplusplus is " << std::to_string(__cplusplus) << endl;
   
    auto givemetime = chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    cout << ctime(&givemetime) << endl;

    return 0;
}
➜  C_C++ git:(main) ✗ clang++ coutToFile.cpp -std=c++11
➜  C_C++ git:(main) ✗ ./a.out 
hello world
学习·现代·西佳佳
__cplusplus is 201103
Wed Jun  7 21:31:42 2023s

3. cout 输出到文件

关键点是, 使用 std::ostream 对象, std::ofstream 对象,以及 std::cout 的 rdbuf() 函数。

3.1 rdbuf() 函数

提供了两个函数, 互为重载版本。第一个函数不带参数, 是getter, 返回流缓冲。

std::basic_streambuf<CharT, Traits>* rdbuf() const;

Manages the associated stream buffer.
Returns the associated stream buffer. If there is no associated stream buffer, returns a null pointer.

第二个函数带参数, 是setter, 设置流缓冲。

std::basic_streambuf<CharT, Traits>* rdbuf( std::basic_streambuf<CharT, Traits>* sb );

Sets the associated stream buffer to sb. The error state is cleared by calling clear(). Returns the associated stream buffer before the operation. If there is no associated stream buffer, returns a null pointer.

3.2 将 cout 内容写入到文件

#include <iostream>
#include <string>
#include <chrono>
#include <ctime>
#include <fstream> // added

int main()
{
    using namespace std;

    ofstream fout("log.txt"); // added
    cout.rdbuf(fout.rdbuf()); // added

    cout << "hello world\n";
    cout << "学习·现代·西佳佳\n";
    cout << "__cplusplus is " << std::to_string(__cplusplus) << endl;
   
    auto givemetime = chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    cout << ctime(&givemetime) << endl;

    return 0;
}
➜  C_C++ git:(main) ✗ clang++ coutToFile.cpp -std=c++17
➜  C_C++ git:(main) ✗ ./a.out 
➜  C_C++ git:(main)cat log.txt 
hello world
学习·现代·西佳佳
__cplusplus is 201703
Wed Jun  7 21:36:46 2023

4. 部分 cout 输出到文件, 部分 cout 输出到控制台

也就是需要能够控制 cout 输出的位置。

4.1 临时切换

#include <iostream>
#include <string>
#include <chrono>
#include <ctime>
#include <fstream> // added

int main()
{
    using namespace std;

    auto stdout_buff = cout.rdbuf();
    ofstream fout("log.txt"); // added
    cout.rdbuf(fout.rdbuf()); // added

    cout << "hello world\n";
    cout << "学习·现代·西佳佳\n";
    cout.rdbuf(stdout_buff);
    cout << "__cplusplus is " << std::to_string(__cplusplus) << endl;
   
    auto givemetime = chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    cout << ctime(&givemetime) << endl;

    return 0;
}

4.2 封装为 class

使用了 RAII 的方式, 获取和恢复 src 的 stream buffer。

如果需要线程安全, 需要对 m_closed 变量加锁。

#include <iostream>
#include <string>
#include <chrono>
#include <ctime>
#include <fstream> // added

class Redirector
{
public:
    Redirector(std::ostream& dst, std::ostream& src) :
        m_src(src),
        m_sbuf(src.rdbuf(dst.rdbuf())),
        m_closed(false)
    {}
    ~Redirector()
    {
        if (!m_closed)
        {
            close();
        }
    }
    void close()
    {
        m_src.rdbuf(m_sbuf);
        m_closed = true;
    }

private:
    std::ostream& m_src;
    std::streambuf* const m_sbuf;
    bool m_closed;
};

int main()
{
    using namespace std;

    std::ofstream log("log2.txt");
    Redirector r(log, std::cout);

    cout << "hello world\n";
    cout << "学习·现代·西佳佳\n";
    r.close();
    
    cout << "__cplusplus is " << std::to_string(__cplusplus) << endl;
   
    auto givemetime = chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    cout << ctime(&givemetime) << endl;

    return 0;
}
➜  C_C++ git:(main) ✗ clang++ coutToFile.cpp -std=c++17
➜  C_C++ git:(main) ✗ ./a.out 
__cplusplus is 201703
Wed Jun  7 21:51:02 2023

➜  C_C++ git:(main)cat log2.txt 
hello world
学习·现代·西佳佳

5. References

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值