C++ IO 库指南

C++ Primer 第八章 标准IO库 学习本章内容之前有必要对缓冲区的概念做一个基本了解,我引用了网上一片文章《C++编程对缓冲区的理解》,内容如下: 什么是缓冲区   缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。   缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓... 阅读详情

前言

如果说算法是程序的"大脑",那么 IO 就是程序的"感官"。C++ 用一套流(Stream)继承体系统一了控制台、文件、字符串的输入输出。

📑 目录


这篇文章会从继承体系 → 状态管理 → 缓冲区机制 → 文件操作 → string 流,讲透 C++ IO 库的全部核心知识。

读完你将收获:

  • 掌握 C++ IO 流家族的继承体系与设计思想
  • 理解四个流状态位(goodbit/eofbit/failbit/badbit)与错误恢复
  • 搞懂输出缓冲区的刷新机制与高性能 IO 的配置方法
  • 熟练使用文件流进行文本/二进制读写,避开深坑
  • 学会用 stringstream 实现数据与字符串的互相转换

1. IO 继承家族

1.1 设计哲学

C++ 语言不直接处理输入输出,而是通过标准库中的一组类来完成 IO 操作。这套类的设计有三大巧妙之处:

  1. 统一接口:无论是控制台、文件还是 string,都使用同一套 << 和 >> 运算符——“一处学会,处处通用”
  2. 继承体系:将通用能力放在基类(ios_base → ios → istream/ostream),将设备专属能力放在派生类
  3. 模板支持:不仅能在 char 上做 IO,也能在 wchar_t 宽字符上做 IO(对应的类和对象都以 w 开头)

1.2 全局对象速查

对象类型绑定设备说明
cinistream标准输入(键盘)默认关联到控制台
coutostream标准输出(屏幕)带缓冲
cerrostream标准错误(屏幕)无缓冲,立即输出
clogostream标准日志(屏幕)带缓冲

2. IO 流状态

2.1 四个状态位

IO 操作中可能会发生各种错误,每个流对象内部维护着一个状态标志字,通过四个位来标记流的健康状况:

状态位含义触发条件是否可恢复
goodbit一切正常流的初始状态,无任何错误✅ 这是目标状态
eofbit到达文件末尾读取时遇到 EOF✅ 可恢复
failbitIO 操作失败(逻辑错误)期望读 int 却读到字符、格式不匹配等✅ 可恢复
badbit流崩溃(系统级错误)不可恢复的底层读写错误❌ 通常无法恢复

重要:这四位是可以组合的位标志——它们定义在 ios_base 基类中,可以作为独立二进制位通过位运算组合。

2.2 实战:cin 读取失败后如何恢复?

这是新手最常遇到的困惑——不小心往数字输入里打了一个字母,此后所有的 cin >> 全都废了:

#include <iostream>
using namespace std;

int main()
{
    // ===== 查看初始状态 =====
    cout << cin.good() << endl;  // 1(正常)
    cout << cin.eof()  << endl;  // 0
    cout << cin.bad()  << endl;  // 0
    cout << cin.fail() << endl;  // 0
    cout << endl;

    int i = 0;

    // ===== 故意输入一个字符(比如 'a'),触发 failbit =====
    cin >> i;
    cout << i << endl;           // 输出:0(读取失败,i 保持原值)

    // ===== 查看失败后的状态 =====
    cout << cin.good() << endl;  // 0(不再正常)
    cout << cin.eof()  << endl;  // 0
    cout << cin.bad()  << endl;  // 0
    cout << cin.fail() << endl;  // 1(failbit 被设置!)
    cout << endl;

    if (cin.fail())
    {
        // ===== 第 1 步:恢复流状态为 goodbit =====
        cin.clear();  // 否则后面的 IO 操作全部会失败!

        // ===== 第 2 步:把缓冲区里的"垃圾字符"读走 =====
        // 否则再去 cin >> i 还会读到那个字符,又失败!
        char ch = cin.peek();            // 偷看一眼缓冲区首字符
        while (!(ch >= '0' && ch <= '9'))
        {
            ch = cin.get();              // 读走一个非数字字符
            cout << "丢弃字符: " << ch << endl;
            ch = cin.peek();             // 再看下一个字符
        }
        cout << endl;
    }

    // ===== 恢复后再次读取 =====
    cout << cin.good() << endl;  // 1(恢复正常!)
    cout << cin.eof()  << endl;  // 0
    cout << cin.bad()  << endl;  // 0
    cout << cin.fail() << endl;  // 0
    cout << endl;

    cin >> i;
    cout << "成功读到: " << i << endl;

    return 0;
}

核心要点:

  1. clear() 只是重置状态位,不会自动清理缓冲区中残留的"垃圾数据"
  2. 恢复流程 = clear() 重置状态 + 手动清空缓冲区中的无效字符
  3. 一个流一旦进入错误状态,后续所有 IO 操作都会自动失败——这是"fail-fast"的防御设计

2.3 eofbit、failbit、badbit 的进阶关系

值得特别关注的是:当到达文件末尾时,eofbit 和 failbit 会被同时设置。这也解释了为什么用 while (cin >> x) 读到文件尾时会退出循环——failbit 被设置导致 operator bool() 返回 false。

另外,setstate() 和 rdstate() 两个函数也能用来操作流状态,具体用法可以参考官方文档。


3. 管理输出缓冲区

3.1 为什么需要缓冲区?

任何输出流都管理着一个输出缓冲区。执行 os << "hello world"; 时,字符串可能被立即输出,也可能被暂时存在缓冲区里,稍后再输出。

为什么要这样做?因为设备写操作非常耗时。有了缓冲区,操作系统可以将多个输出操作合并为一次系统调用,带来可观的性能提升:

无缓冲区:  write("h") → write("e") → write("l") → write("l") → write("o")
           每个字符一次系统调用,5 次!

有缓冲区:  [h][e][l][l][o][ ][w][o][r][l][d]
           攒够一批 → 一次系统调用全部写出去!

3.2 触发缓冲区刷新的 5 种情况

触发条件说明
1. 程序正常结束main 函数 return 时,所有流会被自动刷新关闭
2. 缓冲区满了缓冲区写满时被迫刷新(一般不用你操心)
3. 使用了 endl 或 flushendl = 换行 + 刷新;flush = 只刷新不换行
4. 设置了 unitbuf告诉流每次写后立即刷新;cerr 默认设置了它
5. 关联流发生 IO输出流关联到另一个流时,另一个流一旦读写,输出流就刷新

3.3 实战对比:理解缓冲区的"延迟感"

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

void func(ostream& os)
{
    os << "hello world";
    os << "hello bit";

    // 此时 "hello world" 和 "hello bit" 是否已输出?
    // 答案:不确定!它们可能还在缓冲区里
    system("pause");

    // 加上下面任意一行,前面的内容一定会被刷新:
    // os << endl;      // 方式1:输出换行并刷新
    // os << flush;     // 方式2:只刷新,不换行
    // int i; cin >> i; // 方式3:如果 os 关联了 cin,读 cin 会触发 os 刷新

    os << "hello cat";
    // "hello cat" 是否已输出?——同样不确定
    system("pause");
}

int main()
{
    ofstream ofs("test.txt");

    // 试验 1:默认情况 —— 内容延迟写入
    // func(cout);

    // 试验 2:设置 unitbuf —— 每次写都立即刷新
    // ofs << unitbuf;

    // 试验 3:cin 绑定到 ofs —— 读 cin 时会刷新 ofs 的缓冲区
    // cin.tie(&ofs);

    func(ofs);
    return 0;
}

3.4 tie() —— 流的关联绑定

tie() 函数用于在流之间建立关联:

  • 默认绑定:cin 和 cerr 都被关联到了 cout。这意味着——你每次读 cin 或写 cerr,cout 的缓冲区都会被先刷新。这保证了提示信息和输入操作的顺序正确。
  • 解绑:cin.tie(nullptr) 可以解除 cin 与 cout 的绑定
  • 绑定到别的流:cin.tie(&ofs) 可以让读取 cin 时顺便刷新 ofs 的缓冲区
#include <iostream>
using namespace std;

int main()
{
    // ===== 竞赛必用:高性能 IO 三件套 =====

    // 1. 关闭 C++ 流和 C 流的同步
    //    关闭后,cout 和 printf 的输出顺序就不能保证了!
    ios_base::sync_with_stdio(false);

    // 关闭同步后,下面三行的输出顺序可能是 b a c(而不是 a b c)
    // std::cout << "a\n";
    // std::printf("b\n");
    // std::cout << "c\n";

    // 2 & 3. 解绑 cin 和 cout 与其他流的关联
    cin.tie(nullptr);
    cout.tie(nullptr);

    // 这两行解开后,每次 cin 读取不会触发 cout 刷新
    // 大幅减少系统调用,尤其在大量输入输出的场景下

    return 0;
}

竞赛选手的必备姿势:

ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
// 然后用 '\n' 代替 endl(避免不必要的刷新)

这能让你在使用 cin/cout 时获得接近 scanf/printf 的性能。但关闭同步后绝对不能混用 C 和 C++ 的 IO 函数,否则输出顺序会错乱。


4. 标准 IO 流 —— 你每天都在用却未必真正理解的 cin/cout

4.1 基础回顾

对象类型特点
cinistream标准输入,关联键盘
coutostream标准输出,带缓冲区
cerrostream标准错误,无缓冲(设置了 unitbuf)
clogostream标准日志,带缓冲

4.2 operator bool —— "流能当条件用"的秘密

你有没有好奇过为什么可以写 while (cin >> x)?

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

int main()
{
    int i = 0, j = 1;

    // ===== 为什么 cin >> i >> j 能放在 while 条件里? =====
    // operator>> 的返回值是 istream&(即 cin 本身)
    // cin 这个 istream 对象可以被隐式转换为 bool 值
    //
    // 转换规则:
    //   - goodbit → true  (流正常,可以继续读)
    //   - badbit 或 failbit 被设置 → false  (流不正常,停止)
    //
    while (cin >> i >> j)
    {
        cout << i << " : " << j << endl;
    }
    // 输入 Ctrl+Z 换行可以结束循环
    // Ctrl+Z 会让流读到 EOF → eofbit + failbit → operator bool 返回 false

    // ===== 流状态检查 =====
    cout << cin.good() << endl;  // 0
    cout << cin.eof()  << endl;  // 1(读到文件尾了)
    cout << cin.bad()  << endl;  // 0
    cout << cin.fail() << endl;  // 1
    cout << endl;

    // ===== 流一旦出错就不能再用,需要恢复 =====
    cin.clear();

    string s;
    while (cin >> s)
    {
        cout << s << endl;
    }

    return 0;
}

4.3 几个重要细节

  • istream 和 ostream 是不可拷贝的(拷贝构造和赋值是 delete 的),只能通过引用传递
  • 内置类型(int、double、char* 等)的 << 和 >> 已经在标准库中做好了重载
  • 自定义类型需要我们自己重载 operator<< 和 operator>>

5. 文件 IO 流 —— 从文本读写到二进制序列化

5.1 三个核心类

类继承关系用途
ifstreamistream ← ifstream读文件
ofstreamostream ← ofstream写文件
fstreamiostream ← fstream读写文件

5.2 文件打开模式

文件流可以在构造时打开文件,也可以调用 open() 函数打开文件。这些打开模式是 ios_base 中定义的标志位,可以通过按位或组合使用:

模式含义
in以读方式打开
out以写方式打开
binary以二进制模式打开
ate打开后立即寻位到流结尾(At The End)
app每次写入前寻位到流结尾(APPend)
trunc打开时舍弃(清空)文件原有内容

5.3 app vs ate —— 面试高频考点

这两个模式非常容易搞混:

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

int main()
{
    ofstream ofs("test.txt");

    // ===== 基本写操作 =====
    ofs.put('x');                       // 写单个字符
    ofs.write("hello\nworld", 11);      // 写指定字节数
    ofs << "22222222" << endl;          // 用 << 操作符
    int x = 111;
    double y = 1.11;
    ofs << x << endl;
    ofs << y << endl;
    ofs.close();

    // ===== 实验1:app 模式——永远在文件尾写 =====
    ofs.open("test.txt", ios_base::out | ios_base::app);
    ofs << "1111111" << endl;
    // 即使手动移动写指针到文件头……
    ofs.seekp(0, ios_base::beg);
    // app 模式下,写入还是会发生在文件末尾!
    // seekp 对写入位置无效,因为 app 强制每次写前寻位到尾部
    ofs << x << " " << y << endl;
    ofs.close();

    // ===== 实验2:ate 模式——可自由移动写指针 =====
    ofs.open("test.txt", ios_base::out | ios_base::ate);
    ofs << "1111111" << endl;           // 打开后在末尾,所以追加
    ofs.seekp(0, ios_base::beg);        // 移动到文件头
    ofs << x << " " << y << endl;       // 从头部覆盖写!
    ofs.close();

    return 0;
}

一句话区别:

  • app = 每次写入强制在文件尾部追加,你无法通过 seekp 改变写入位置
  • ate = 只是在文件打开瞬间跳到文件尾,之后你可以用 seekp 去任何位置写

5.4 out vs out|trunc —— trunc 到底有没有必要?

// 以下两种写法在当前主流实现中行为一致:
ofs.open("test.txt", ios_base::out);
ofs.open("test.txt", ios_base::out | ios_base::trunc);
// 两者都会先把文件内容清空,再开始写

// 那 trunc 存在的意义是什么?
// 1. 语义明确:out|trunc 更清楚地表达了"有内容就清掉"的意图
// 2. 跨平台保险:在某些非主流实现中,out 的行为可能不完全等同于截断

5.5 文件读写的常用函数

ifstream 的读函数:get()(读一个字符)、read()(读指定字节)、>>(格式化读)

ofstream 的写函数:put()(写一个字符)、write()(写指定字节)、<<(格式化写)

5.6 实战:二进制复制图片文件

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

int main()
{
    // 必须以 binary 模式打开,否则图片中的某些字节会被错误解释
    ifstream ifs("source.png", ios_base::in | ios_base::binary);
    ofstream ofs("copy.png", ios_base::out | ios_base::binary);

    int n = 0;
    while (ifs && ofs)
    {
        char ch = ifs.get();
        ofs << ch;
        ++n;
    }
    cout << "复制完成,共 " << n << " 字节" << endl;

    return 0;
}

5.7 进阶实战:自定义类型的二进制与文本读写

这个例子综合展示了文件 IO 的核心能力,也是项目中最常见的需求——配置文件的读写:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

// ===== 自定义 Date 类,重载了 IO 运算符 =====
class Date
{
    friend ostream& operator << (ostream& out, const Date& d);
    friend istream& operator >> (istream& in, Date& d);
public:
    Date(int year = 1, int month = 1, int day = 1)
        :_year(year)
        , _month(month)
        , _day(day)
    {}
private:
    int _year;
    int _month;
    int _day;
};

istream& operator >> (istream& in, Date& d)
{
    in >> d._year >> d._month >> d._day;
    return in;
}

ostream& operator << (ostream& out, const Date& d)
{
    out << d._year << " " << d._month << " " << d._day;
    return out;
}

// ===== 服务器配置信息结构体 =====
struct ServerInfo
{
    // 二进制读写时,这里千万不能用 string!!
    // 原因:string 对象中存储的是指向堆上字符数组的指针
    // 如果直接二进制 write(&info, sizeof(info))
    // 写出去的是指针的值(一个地址),不是字符串内容!
    // 再读回来时,指针指向的位置可能已经无效了 → 野指针!
    char _address[32];      // ✅ 二进制安全
    // string _address;     // ❌ 二进制不安全!
    int _port;
    Date _date;
};

// ===== 配置文件管理器 =====
struct ConfigManager
{
public:
    ConfigManager(const char* filename)
        :_filename(filename)
    {}

    // ---------- 二进制写 ----------
    // "内存中怎么存的,就囫囵吞枣怎么直接写出去"
    void WriteBin(const ServerInfo& info)
    {
        ofstream ofs(_filename, ios_base::out | ios_base::binary);
        // 把 info 的内存块原封不动写出去
        ofs.write((const char*)&info, sizeof(info));
    }

    // ---------- 二进制读 ----------
    // "文件中的内容直接囫囵吞枣读到内存中"
    void ReadBin(ServerInfo& info)
    {
        ifstream ifs(_filename, ios_base::in | ios_base::binary);
        ifs.read((char*)&info, sizeof(info));
    }

    // ---------- 文本写 ----------
    void WriteText(const ServerInfo& info)
    {
        ofstream ofs(_filename);
        // 利用重载好的 << 逐个字段写
        ofs << info._address << " " << info._port << " " << info._date;
    }

    // ---------- 文本读 ----------
    void ReadText(ServerInfo& info)
    {
        ifstream ifs(_filename);
        // 利用重载好的 >> 逐个字段读
        ifs >> info._address >> info._port >> info._date;
    }

private:
    string _filename;
};

// ===== 测试 =====
void WriteBin()
{
    ServerInfo winfo = { "192.0.0.1", 80, { 2025, 1, 10 } };
    ConfigManager cf_bin("test.bin");
    cf_bin.WriteBin(winfo);
}

void ReadBin()
{
    ConfigManager cf_bin("test.bin");
    ServerInfo rbinfo;
    cf_bin.ReadBin(rbinfo);
    cout << rbinfo._address << " " << rbinfo._port << " " << rbinfo._date << endl;
}

void WriteText()
{
    ServerInfo winfo = { "192.0.0.1", 80, { 2025, 1, 10 } };
    ConfigManager cf_text("test.txt");
    cf_text.WriteText(winfo);
}

void ReadText()
{
    ConfigManager cf_text("test.txt");
    ServerInfo rtinfo;
    cf_text.ReadText(rtinfo);
    cout << rtinfo._address << " " << rtinfo._port << " " << rtinfo._date << endl;
}

int main()
{
    WriteBin();
    ReadBin();      // 二进制读写验证
    WriteText();
    ReadText();     // 文本读写验证
    return 0;
}

🚨 二进制读写的致命陷阱:

结构体中包含 string 成员时,绝对不要用 write() / read() 做二进制读写!

原因图解:

string 对象的实际内存布局:
┌─────────────────────┐
│  _Ptr  ───────────────→ 堆上的字符数组 "192.0.0.1"
│  _Size               │
│  _Capacity           │
└─────────────────────┘

write(&info, sizeof(info)) 写出的是 _Ptr 的值(一个地址值,如 0x1A2B3C4D)
而不是 "192.0.0.1" 这个字符串本身!

当程序重新运行,read 回来时:
  _Ptr = 0x1A2B3C4D  ← 这个地址早就失效了!
  访问 = 野指针 = 崩溃

解决方案:

  • 二进制读写用 char _address[32] 这种定长字符数组(数组内容直接存在结构体内存中)
  • 或者用文本读写(<< 和 >>),string 的重载会正确处理

5.8 文本读写 vs 二进制读写 对比

维度文本读写二进制读写
可读性✅ 人可直接阅读❌ 乱码,不可读
文件大小较大(数字要转字符串)较小(原样存储)
string 支持✅ 安全❌ 致命bug
跨平台❌ 文本格式可能不同❌ 字节序/对齐可能不同
适用场景配置文件、日志图片、音视频、性能敏感

6. string IO 流 —— 内存中的"字符串瑞士军刀"

6.1 三个类

类继承关系用途
istringstreamistream ← istringstream从 string 读
ostringstreamostream ← ostringstream往 string 写
stringstreamiostream ← stringstream双向读写

底层都维护了一个 string 对象来保存数据,通过 str() 函数获取或设置。

6.2 基础用法:数据类型 ↔ 字符串

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

int main()
{
    // ===== 数据 → 字符串(ostringstream) =====
    int i = 123;
    Date d = { 2025, 4, 10 };

    ostringstream oss;
    oss << i << endl;
    oss << d << endl;

    string s = oss.str();  // 获取底层 string 对象
    cout << s << endl;     // 输出:123\n2025 4 10

    // ===== 字符串 → 数据(istringstream) =====
    // 方式1:构造时传入字符串
    istringstream iss("100 2025 9 9");

    // 方式2:用 str() 设置底层字符串
    // istringstream iss;
    // iss.str("100 2025 9 9");

    int j;
    Date x;
    iss >> j >> x;
    cout << j << endl;      // 输出:100
    cout << x << endl;      // 输出:2025 9 9

    return 0;
}

6.3 必须警惕:重复使用 stringstream 的坑

这是一个极易踩中的陷阱:

int main()
{
    int a = 1234;
    int b = 5678;
    string str;

    stringstream ss;
    ss << a << " " << b;

    // 注意:>> 遇到空格就停了,这里只会读到 "1234"
    ss >> str;
    cout << str << endl;           // 输出:1234
    cout << ss.fail() << endl;     // 0(还没读完)
    cout << ss.bad()  << endl;     // 0

    // ========== 陷阱!第一次用完后想接着用 ==========
    // stringstream 在读到流尾时,会设置 eofbit 和 failbit
    // 如果不重置状态,后续的 << 和 >> 全部失效!

    // ===== 正确做法:两步必须都做 ====
    // 第 1 步:重置流状态位为 goodbit
    ss.clear();
    // 第 2 步:清空底层 string 的内容
    ss.str("");

    double dd = 12.34;
    ss << dd;
    ss >> str;
    cout << str << endl;           // ✅ 成功输出:12.34

    return 0;
}

核心结论:重复使用 stringstream 时,必须同时调用 clear() 和 str("")。前者重置状态位,后者清空数据。只调用 clear() 不清空数据,会导致老数据残留;只调用 str("") 不重置状态,会导致流仍然处于失败状态。

6.4 综合实战:聊天信息序列化

这是 stringstream 在真实项目中的经典应用——将结构体数据序列化为字符串,通过网络发送后再反序列化回来:

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

// ===== Date 类(同上,省略构造函数细节) =====
class Date
{
    friend ostream& operator << (ostream& out, const Date& d);
    friend istream& operator >> (istream& in, Date& d);
public:
    Date(int year = 1, int month = 1, int day = 1)
        :_year(year), _month(month), _day(day) {}
private:
    int _year, _month, _day;
};

istream& operator >> (istream& in, Date& d)
{
    in >> d._year >> d._month >> d._day;
    return in;
}

ostream& operator << (ostream& out, const Date& d)
{
    out << d._year << " " << d._month << " " << d._day;
    return out;
}

// ===== 聊天消息结构体 =====
struct ChatInfo
{
    string _name;   // 名字
    int    _id;     // ID
    Date   _date;   // 时间
    string _msg;    // 聊天信息
};

int main()
{
    // ==================== 序列化(结构体 → 字符串)====================
    ChatInfo sendInfo = { "张三", 135246, { 2022, 4, 10 }, "晚上一起看电影吧" };

    ostringstream oss;
    oss << sendInfo._name << " "
        << sendInfo._id   << " "
        << sendInfo._date << " "
        << sendInfo._msg;

    string str = oss.str();
    cout << "序列化后的字符串:" << str << endl << endl;

    // ===== 实际开发中,这个字符串就可以通过网络发给对方了 =====
    // 更复杂的场景一般会用 JSON、XML、Protobuf 等来序列化

    // ==================== 反序列化(字符串 → 结构体)====================
    ChatInfo recvInfo;
    istringstream iss(str);
    iss >> recvInfo._name
        >> recvInfo._id
        >> recvInfo._date
        >> recvInfo._msg;

    // ===== 恢复成结构化数据显示 =====
    cout << "-------------------------------------------------------" << endl;
    cout << "姓名:" << recvInfo._name << "(" << recvInfo._id << ") ";
    cout << recvInfo._date << endl;
    cout << recvInfo._name << ":>" << recvInfo._msg << endl;
    cout << "-------------------------------------------------------" << endl;

    return 0;
}

运行结果:

序列化后的字符串:张三 135246 2022 4 10 晚上一起看电影吧

-------------------------------------------------------
姓名:张三(135246) 2022 4 10
张三:>晚上一起看电影吧
-------------------------------------------------------

局限性说明:这种空格分隔的简单序列化方案只适用于字段中不含空格的简单场景。真实项目中消息往往包含空格、换行等复杂的结构化数据,通常会选用 JSON、XML 或 Protobuf 来承载。


7. 总结与最佳实践

7.1 知识地图

C++ IO 库
├── 继承体系
│   ├── ios_base → ios → istream/ostream
│   ├── 控制台:cin, cout, cerr, clog
│   ├── 文件:ifstream, ofstream, fstream
│   └── 字符串:istringstream, ostringstream, stringstream
├── 流状态管理
│   ├── goodbit(正常)
│   ├── eofbit(文件尾)
│   ├── failbit(逻辑错误,可恢复)
│   ├── badbit(系统错误,不可恢复)
│   └── clear() 恢复,peek()/get() 清理缓冲区
├── 缓冲区管理
│   ├── endl/flush/unitbuf 刷新
│   ├── tie() 绑定关联流
│   └── sync_with_stdio(false) 提速
├── 文件操作
│   ├── 打开模式:in, out, binary, ate, app, trunc
│   ├── 文本读写:<< 和 >> 运算符
│   ├── 二进制读写:write() 和 read()
│   └── ⚠️ string 成员不能用二进制读写
└── 字符串流
    ├── 数据 ↔ string 互转
    ├── 序列化与反序列化
    └── ⚠️ 重复使用需 clear() + str("")

7.2 最佳实践清单

  1. 优先选用 C++ 流:相比于 C 语言的 printf/scanf,C++ 流更类型安全、更易扩展——你只需要重载 << 和 >>,自定义类型就能无缝融入 IO 体系。

  2. 竞赛场景加速三件套:

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    // 然后用 '\n' 代替 endl
    
  3. 流状态出错后,恢复两步走:clear() 重置状态位 + 手动消费掉缓冲区中的垃圾数据。

  4. 二进制读写避免 string 成员:改用定长 char 数组,或选用文本方式读写。

  5. 重复使用 stringstream 时,务必 clear() + str("") 一起调用。

  6. app vs ate:记住 app 是每次写都强制追加(无视 seekp),ate 只是打开时跳到末尾(之后可以自由移动指针)。

  7. 日常开发用 '\n' 而非 endl:除非你确实需要马上刷新缓冲区(比如日志输出),否则 endl 带来的额外刷新只是浪费性能。

  8. 查阅文档是个好习惯:cplusplus.com 和 cppreference.com 是最可靠的参考。

7.3 写在最后

C++ 的 IO 库是一套经过几十年工业验证的成熟设计。它的继承体系让你"学会一个接口,处处都能使用";它的状态管理让你能写出健壮的输入处理逻辑;它的缓冲区和流绑定机制让 IO 性能可调可控。


如果这篇文章对你有帮助,欢迎点赞、收藏、关注三连! 🎉

C++标准库实战指南 C++标准库是C++语言的基石,包含了一组预先定义的类和函数,以便于在编写C++程序时直接使用。这些组件构成了标准模板库(STL)、语言运行时库以及诊断等部分。设计它的初衷是为了提供一种标准的方法来处理常见的编程任务,如输入输出、字符串处理、容器操作、算法应用和日期时间处理等,从而避免程序员重复发明轮子。库中的组件大体上可以分为三类:1. 语言支持库,包括了C++的语法基础,例如类型、类型转换操作符等。2. 标准库组件,覆盖广泛功能,如容器、迭代器、算法、函数对象、字符串和流等。 阅读详情

相关推荐

简易电梯控制系统设计(两层楼)(

(电子科技大学 数字系统实验二 结课验收项目 ) 题目要求:

m0_48801027的博客 1万+

Socket.IO-Client-CPP 安装和配置指南

### 项目基础介绍 Socket.IO-Client-CPP 是一个 C++11 实现的 Socket.IO 客户端库。Socket.IO 是一个流行的 JavaScript 库,提供实时、双向的通信功能。通过使用 C++ 编写,此客户端库可以在多个不同的平台上工作,包括 Windows、Linux 和 macOS 等。 ### 主要的编程语言 该项目主要使用 C++11 进行开发,利用现代 ...

gitblog_07542的博客 664

无人机室内悬停如何稳?光流与IMU数据融合实战解析

在无GPS的室内环境中,无人机自主悬停依赖多传感器融合,其中光流与IMU是核心组合。光流传感器通过图像像素位移估算相对地面的速度,长期无漂移,但易受光照和纹理影响;IMU高频响应出色,却存在积分累积漂移。两者在频率与误差特性上天然互补,融合后可实现高精度位置估计。工程实践中,需合理选型、正确处理坐标变换与时间对齐,并通过互补滤波或扩展卡尔曼滤波将光流速度修正引入状态估计,进而支撑位置环与速度环控制。这一技术不仅解决室内定点悬停,也为视觉惯性里程计等更复杂的自主定位提供基础。本文结合真实调试案例,梳理从硬件安

weixin_33314040的博客 293

Socket.IO C++客户端库安装指南

Socket.IO C++客户端库为开发者提供了在C++项目中实现实时双向通信的能力。本文将详细介绍该库在不同环境下的安装方法,帮助开发者快速集成到项目中。 ## CMake安装方式(推荐) 对于现代C++项目,使用CMake进行构建是最为推荐的方式,具有依赖管理自动化、跨平台兼容性好等优势。 ### 安装步骤 1. **克隆仓库** 使用递归克隆命令获取完整代码库,确保获取所有...

gitblog_00843的博客 602

四、嘉立创EDA原理图绘制实战:从零搭建STM32温湿度监测系统

本文详细介绍了使用嘉立创EDA标准版从零开始绘制STM32温湿度监测系统原理图的完整流程。涵盖核心元器件选型、电源电路设计、ADC按键创新应用及模块化布局技巧,帮助电子爱好者快速掌握STM32系统设计,提升嵌入式开发实战能力。

h0i1j2k3l的博客 883

从零到一:手把手教你用STM32F103C8T6打造个人专属开发板(附立创EDA工程与源码)

本文详细介绍了如何使用STM32F103C8T6微控制器从零开始设计和制作个人专属开发板。内容涵盖硬件选型、原理图设计、PCB布局、功能验证等全流程,并提供了立创EDA工程文件和源码,帮助开发者深入理解STM32开发板的硬件架构与设计要点。

weixin_26802933的博客 284

【C++拓展】吃透 C++ IO 库:从控制台到文件 / 字符串的全场景实战指南

本文全面解析C++ IO库,从底层设计到实战应用。首先介绍IO库的继承体系,包括ios_base、basic_ios等核心类及其模板参数设计。重点讲解流状态管理机制,详细说明goodbit、eofbit等状态标志及其处理方法。深入剖析输出缓冲区原理,解释5种缓冲区刷新场景及性能优化技巧。 针对三大IO场景提供详细指导:标准IO流(cin/cout)的基础用法与自定义类型支持;文件IO流的文本/二进制读写、指针定位和文件复制;字符串IO流的数据转换与序列化技术。

2301_79248256的博客 1799

fatal: unable to access ‘https://github.com/xxx.git/‘ OpenSSL SSL_connect: SSL_ERROR_SYSCALL 解决方案

 本文主要介绍了fatal: unable to access ‘https://github.com/xxx.git/’: OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443解决方案,希望能对使用git的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 24万+

终极内存映射指南:mio库让C++文件IO性能飙升10倍

在当今数据密集型应用的时代,文件IO性能往往成为系统瓶颈。传统的读写操作需要频繁的系统调用和数据拷贝,效率低下。mio内存映射库作为跨平台C++11头文件库,彻底改变了这一局面,让文件IO性能实现质的飞跃!🚀 mio是一个轻量级的C++内存映射文件库,采用MIT许可证,无需依赖Boost等重型库,即可实现高效的文件内存映射操作。通过将文件直接映射到进程的地址空间,mio绕过了传统IO的系统调用

gitblog_00347的博客 941

【OpenClaw从入门到精通】第19篇:OpenClaw电商实战:从零搭建比价+库存监控+自动调价全自动化系统(2026实测附完整代码)

2026年OpenClaw成为全球最火开源项目,电商行业因其场景高频、数据标准化成为其核心落地领域。本文针对电商从业者面临的比价繁琐、库存混乱、调价滞后三大痛点,基于OpenClaw的“接入层-执行层-决策层”三层架构,从零拆解智能比价、多平台库存监控、动态自动调价三大核心场景的实现逻辑。文中包含完整的环境配置、技能安装、代码实现(含Python脚本与YAML配置)、执行结果验证,同时补充关键算法原理与避坑指南,兼顾新手入门与进阶提升。读者可直接参考本文实操流程,快速搭建属于自己的电商自动化系统,实现7×2

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 2236

如何离线环境下安装Dify插件 (可提供远程指导协助)

离线环境下安装Dify插件

litlit023的专栏 8100

终极指南:如何使用mio内存映射库提升C++文件IO性能

在C++开发中,处理大文件或需要高性能IO操作的场景时,传统文件读写方式往往成为性能瓶颈。今天,我要介绍一个改变游戏规则的工具——mio内存映射库,这是一个跨平台的C++11头文件库,能够让你的文件操作速度提升数倍!😊 mio是一个基于MIT许可证的开源项目,它为开发者提供了简洁而强大的内存映射文件IO功能。这个库最大的优势在于它完全无依赖,只需包含一个头文件就能在任何C++项目中使用,支持W

gitblog_00092的博客 927

基于DINO自监督学习对YOLO11 Backbone进行预训练

这PoolHead将获取前一层的输出并应用卷积,然后应用自适应平均池化以将特征图的空间维度减小为固定且一致的大小(1x1)。这是必需的,因为否则空间维度会根据输入的大小而变化,这将使将 DINO 头部附加到主干变得困难,因为它需要固定的输入大小。在本指南中,我们将介绍如何使用 Lightly 使用 DINO 预训练 YOLO 11主干,以及如何将其重新加载到 Ultralytics 中进行微调。您可以使用不同的大小,例如,640这与 YOLO 中的默认图像大小更一致,但它也会在训练期间消耗更多 VRAM。

如果想成为中心,那么就到中心去吧。 1014

终极指南:如何使用mio库实现高性能C++内存映射文件IO

你是否曾经在处理大文件时感到性能瓶颈?是否想要一种更高效的文件读写方式?今天我要向你介绍一个改变游戏规则的工具——mio内存映射库!这是一个跨平台的C++11头文件库,专门为需要高性能文件IO的开发者设计。mio库让你能够像操作内存一样轻松处理文件,大幅提升数据处理效率。 ## 为什么选择mio内存映射库? 想象一下,你正在开发一个需要处理数GB大文件的应用,传统的文件读写方式让你等待了太久。

gitblog_00966的博客 745

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

mio内存映射库终极指南:提升C++文件IO性能的10个实用技巧

mio是一个跨平台的C++11头文件内存映射库,采用MIT许可证,为开发者提供了高效的文件IO操作解决方案。作为内存映射的最佳实践工具,mio让文件处理变得简单而强大,无需依赖Boost库即可实现高性能文件读写。 ## 🔥 为什么选择mio内存映射库? 内存映射技术是文件处理领域的革命性进步!与传统文件IO相比,mio内存映射库具有以下核心优势: - **零成本抽象**:mio是对系统特定

gitblog_00144的博客 1162

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

终极内存映射指南:如何用mio库在C++11中实现高性能文件IO

在现代高性能C++开发中,处理大文件IO操作经常成为性能瓶颈。传统文件读写方式需要频繁的系统调用和内存拷贝,当处理GB级别文件时,这种开销变得不可忽视。本文将深入探讨如何通过mio内存映射库,在C++11项目中实现零拷贝文件操作,大幅提升IO性能。 ## 🎯 内存映射的技术挑战与解决方案 ### 传统文件IO的性能瓶颈 在传统文件IO模型中,数据需要在用户空间和内核空间之间来回拷贝,这个过

gitblog_00876的博客 948

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

C++ IO库实战指南:从流抽象到控制台、文件与字符串处理

在C++编程中,输入输出(IO)是连接程序与外部世界的基础。其核心设计哲学是“流”抽象,它将数据流动统一为从源到目的地的管道,通过缓冲区机制平衡性能与实时性。这一设计使得开发者能用同一套操作模型处理控制台交互、文件持久化及内存字符串转换,极大提升了代码的复用性与可维护性。理解流的层次结构、状态管理及缓冲原理,对于编写健壮、高效的代码至关重要。在实际应用中,开发者常面临控制台中文乱码、文件读写效率低下及字符串解析等挑战。本文聚焦C++ IO库,深入探讨其流模型、缓冲区机制及跨平台编码问题,提供从基础概念到高级

weixin_31423955的博客 225

JoyCon-Driver 构建指南:Socket.IO C++ 客户端依赖中的 Boost 库安装与编译

> 本文基于 [socket.io-client-cpp](https://link.gitcode.com/i/de2c90d87fe9270040e840fc92872163) 官方文档中的 Boost 构建章节编写。Socket.IO C++ 客户端是 JoyCon-Driver 实现"广播模式(Broadcast Mode)"(将手柄按键/摇杆状态通过 `sendControllerSta

gitblog_00106的博客 220

fast_io:C++20高性能I/O库的终极指南 - 为什么它比标准库快10倍?

fast_io是一个基于C++20标准的输入输出库,旨在替代常用的`<iostream>`和`<cstdio>`库,提供卓越的性能。作为一个仅包含头文件的库,它可以轻松集成到任何项目中,且采用Anti-Tivo许可证。不过,使用它需要支持概念的C++20编译器。 ### 为什么选择fast_io? `fast_io`中的“fast”并不一定意味着它是最快的输入输出库(否则应该命名为`faste

gitblog_00903的博客 414

Socket.IO-Client-cpp的使用——C++

Socket.IO C++基于Boost和WebSocket++,可在多平台上工作(跨平台)。此通信类似于websocket,但是不通用于websocket。

xiaopei_yan的博客 3382

网络编程与异步IO库全面剖析 本文深入探讨了现代C++网络编程中的四个核心异步IO库:Boost.Asio跨平台异步IO框架、libuv(Node.js底层库)、C++ REST SDK以及WebSo...

网络编程与异步IO库全面剖析 本文深入探讨了现代C++网络编程中的四个核心异步IO库:Boost.Asio跨平台异步IO框架、libuv(Node.js底层库)、C++ REST SDK以及WebSocket++。全面解析了各库的架构设计、核心特性、编程模型和实际应用场景,为开发者提供高性能网络应用开发的完整技术指南。 Boost.Asio:跨平台异步IO编程框架 Boost.Asio是C++网络...

gitblog_00559的博客 1271

xtensor-python: Python绑定_xtensor库的实战指南

xtensor-python: Python绑定_xtensor库的实战指南 项目介绍 xtensor-python 是一个强大的Python库,它提供了对 xtensor——一个高级的C++多维数组库——的无缝访问。此项目使得开发者能够利用numpy风格的数据处理能力,包括广播机制和延迟计算,同时享受C++提供的性能优势。通过 xtensor-python,用户可以原地操作numpy数组,并访问...

gitblog_00024的博客 796

linux下C/C++语言socket.io库的编译和使用

linux下C/C++语言socket.io库的编译和使用

m0_37915666的博客 3417

C++Primer学习——第8章 IO库

文章目录IO库IO类IO库类型和头文件IO类型之间的关系IO对象无拷贝或赋值条件状态IO库条件状态刷新输出缓冲区unitbuf操纵符关联输入和输出流文件输入输出fstream特有的操作open和close文件模式指定文件模式的限制:以out模式打开文件会丢弃已有数据string流stringstream 特有的操作 IO库 IO类 IO库类型和头文件 头文件 类型 iostream istream, wistream 从流读取数据; ostream, wostream向流写入数据;iost

m0_47598872的博客 383

【C++】IO库

C++标准库通过继承家族类体系实现灵活高效的IO操作,主要包含控制台IO、文件IO和字符串IO三大类。核心设计结合模板与继承,支持char和wchar_t两种字符类型,通过basic_istream/basic_ostream等基类模板派生具体流类。流状态管理通过goodbit、eofbit等状态位实现错误处理,缓冲区机制提升IO性能。文件流支持二进制/文本模式读写,字符串流提供数据序列化功能。这种设计实现接口一致性、代码复用和扩展性,开发者可统一使用<<和>>运算符进行各种IO操作

2402_82670467的博客 1399

【C++】IO库 && IO流

【C++】 IO库 && IO流,一文带你搞懂C++的 IO流

tan_run的博客 1999
上一篇: C++类型转换完全指南
下一篇: 二叉树进阶算法题详解
jinyishu_
博客等级 码龄1年 53粉丝 82原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值