
在 C++ 编程中,输入输出(I/O)是程序与外部世界交互的桥梁。无论是从键盘读取数据、向屏幕输出结果,还是读写文件、处理字符串,都离不开 C++ 标准库提供的流类库。本章将全面解析 C++ 流类库的结构与使用,从基础的控制台 I/O 到文件操作、字符串流,再到高级的对象串行化,带你掌握 C++ 中所有 I/O 操作的核心技能。
"流"(Stream)是 C++ 中对数据传输的抽象概念。想象水流从一个地方流向另一个地方,数据也像水流一样在程序与外部设备(键盘、屏幕、文件等)之间传输:
C++ 流类库以类层次结构实现,核心类定义在<iostream>、<fstream>、<sstream>等头文件中。
@startuml
class ios {
+ enum openmode { in, out, app, ate, trunc, binary }
+ enum seekdir { beg, cur, end }
+ bool good()
+ bool eof()
+ bool fail()
+ bool bad()
+ void clear()
+ operator bool()
}
class istream {
+ istream& operator>>(T& val)
+ int get()
+ istream& get(char& c)
+ istream& getline(char* buf, int count)
+ istream& read(char* buf, streamsize count)
+ streampos tellg()
+ istream& seekg(streampos pos)
}
class ostream {
+ ostream& operator<<(T val)
+ ostream& put(char c)
+ ostream& write(const char* buf, streamsize count)
+ streampos tellp()
+ ostream& seekp(streampos pos)
+ ostream& flush()
}
class iostream {
// 继承istream和ostream的功能
}
class ifstream {
+ ifstream()
+ ifstream(const char* filename, openmode mode = in)
+ bool is_open()
+ void open(const char* filename, openmode mode = in)
+ void close()
}
class ofstream {
+ ofstream()
+ ofstream(const char* filename, openmode mode = out)
+ bool is_open()
+ void open(const char* filename, openmode mode = out)
+ void close()
}
class fstream {
+ fstream()
+ fstream(const char* filename, openmode mode = in|out)
+ bool is_open()
+ void open(const char* filename, openmode mode = in|out)
+ void close()
}
class istringstream {
+ istringstream()
+ istringstream(const string& str)
+ string str() const
}
class ostringstream {
+ ostringstream()
+ string str() const
+ void str(const string& s)
}
class stringstream {
// 继承istringstream和ostringstream的功能
}
ios <|-- istream
ios <|-- ostream
istream <|-- iostream
ostream <|-- iostream
istream <|-- ifstream
ostream <|-- ofstream
iostream <|-- fstream
istream <|-- istringstream
ostream <|-- ostringstream
iostream <|-- stringstream
@enduml

输出流用于将程序中的数据传输到外部设备(屏幕、文件等),C++ 中最常用的输出流是cout(控制台输出)、ofstream(文件输出)和ostringstream(字符串输出)。
输出流对象的构造主要涉及控制台输出流、文件输出流的初始化。
#include <iostream>
#include <fstream> // 文件流头文件
using namespace std;
int main() {
// 1. 控制台输出流(全局对象,无需手动构造)
cout << "这是控制台输出流" << endl;
// 2. 文件输出流构造方式1:默认构造+open()
ofstream ofs1;
// 打开文件(若文件不存在则创建,存在则清空内容)
ofs1.open("output1.txt", ios::out); // ios::out是默认模式,可省略
if (ofs1.is_open()) { // 检查文件是否成功打开
ofs1 << "用ofs1写入的内容" << endl;
ofs1.close(); // 操作完成后关闭文件
} else {
cerr << "ofs1打开文件失败!" << endl;
}
// 3. 文件输出流构造方式2:构造函数直接打开
ofstream ofs2("output2.txt", ios::out | ios::app); // 追加模式
if (ofs2) { // 流对象可直接作为布尔值判断是否正常
ofs2 << "用ofs2追加的内容" << endl;
ofs2.close();
} else {
cerr << "ofs2打开文件失败!" << endl;
}
return 0;
}
<<是输出流的插入运算符,用于输出数据;操纵符(Manipulator)用于控制输出格式(如对齐、精度等)。
操纵符 | 功能 | 头文件 |
|---|---|---|
endl | 换行并刷新缓冲区 | <iostream> |
ends | 输出空字符\0 | <iostream> |
flush | 刷新缓冲区 | <iostream> |
setw(n) | 设置输出宽度为 n | <iomanip> |
setfill(c) | 设置填充字符为 c | <iomanip> |
setprecision(n) | 设置浮点数精度 | <iomanip> |
fixed | 固定小数位格式 | <iomanip> |
left/right/internal | 左对齐 / 右对齐 / 内部对齐 | <iomanip> |
hex/oct/dec | 十六进制 / 八进制 / 十进制输出 | <iostream> |
#include <iostream>
#include <iomanip> // 格式操纵符头文件
using namespace std;
int main() {
// 基本数据输出
int a = 100;
double b = 3.1415926535;
char c = 'A';
string s = "Hello C++";
cout << "整数:" << a << endl;
cout << "浮点数:" << b << endl;
cout << "字符:" << c << endl;
cout << "字符串:" << s << endl << endl;
// 格式控制示例
cout << "===== 格式控制演示 =====" << endl;
// 宽度与填充
cout << "默认宽度:" << a << endl;
cout << "设置宽度10:" << setw(10) << a << endl; // 右对齐,宽度不足用空格填充
cout << "左对齐+填充:" << setw(10) << left << setfill('*') << a << endl; // 左对齐,用*填充
cout << resetiosflags(ios::left); // 重置对齐方式(恢复默认)
// 浮点数精度控制
cout << "\n浮点数精度演示:" << endl;
cout << "默认精度:" << b << endl; // 默认6位有效数字
cout << "setprecision(8):" << setprecision(8) << b << endl; // 8位有效数字
cout << "fixed+precision(4):" << fixed << setprecision(4) << b << endl; // 固定4位小数
// 进制转换
cout << "\n进制转换演示:" << endl;
cout << "十进制:" << dec << a << endl; // 十进制(默认)
cout << "八进制:" << oct << a << endl; // 八进制
cout << "十六进制:" << hex << a << endl; // 十六进制(小写)
cout << "十六进制大写:" << uppercase << hex << a << endl; // 十六进制大写
return 0;
}
除了<<运算符,输出流还提供了put()、write()等成员函数用于输出操作。
函数 | 功能 |
|---|---|
put(char c) | 输出单个字符 |
write(const char* buf, streamsize n) | 输出缓冲区 buf 中的 n 个字节 |
tellp() | 返回当前写位置 |
seekp(pos) | 设置写位置 |
flush() | 刷新输出缓冲区 |
close() | 关闭文件 |
#include <iostream>
#include <fstream>
#include <cstring> // 用于strlen
using namespace std;
int main() {
ofstream ofs("member_func.txt");
if (!ofs) {
cerr << "文件打开失败!" << endl;
return 1;
}
// put():输出单个字符
ofs.put('H');
ofs.put('i');
ofs.put('\n'); // 换行
// write():输出字节序列(适合二进制数据)
const char* str = "使用write()写入的字符串";
// 注意:write()不会自动添加结束符,需手动控制长度
ofs.write(str, strlen(str));
ofs.put('\n');
// tellp():获取当前写位置
streampos pos = ofs.tellp();
cout << "当前写位置:" << pos << endl;
// 写入一些内容
ofs << "这是一段测试文本" << endl;
// seekp():移动写位置到开头
ofs.seekp(0, ios::beg); // ios::beg表示从文件开头计算
ofs << "替换开头内容"; // 覆盖开头部分
ofs.close(); // 关闭文件
cout << "操作完成,请查看member_func.txt" << endl;
return 0;
}
二进制文件直接存储数据的内存表示,适合存储结构化数据(如结构体)。与文本文件的区别是:二进制文件读写需指定ios::binary模式,且通常使用write()/read()函数。
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// 定义一个结构体表示学生信息
struct Student {
int id; // 学号
char name[20]; // 姓名(固定长度,避免字符串指针问题)
float score; // 成绩
};
int main() {
// 1. 创建学生数据
Student s1 = {1001, "张三", 95.5f};
Student s2 = {1002, "李四", 88.0f};
Student s3 = {1003, "王五", 92.3f};
// 2. 二进制模式打开文件(ios::binary)
ofstream ofs("students.dat", ios::out | ios::binary);
if (!ofs) {
cerr << "文件打开失败!" << endl;
return 1;
}
// 3. 用write()写入二进制数据
// write()参数:数据地址(需强转为char*)、数据大小
ofs.write(reinterpret_cast<const char*>(&s1), sizeof(s1));
ofs.write(reinterpret_cast<const char*>(&s2), sizeof(s2));
ofs.write(reinterpret_cast<const char*>(&s3), sizeof(s3));
ofs.close();
cout << "二进制文件写入完成!" << endl;
return 0;
}
ostringstream用于将数据写入字符串缓冲区,可实现 "字符串拼接" 或 "数据格式化转字符串" 功能,定义在<sstream>头文件中。
#include <iostream>
#include <sstream> // 字符串流头文件
#include <string>
#include <iomanip> // 包含setprecision等格式化操纵符的头文件
using namespace std;
int main() {
// 1. 基本使用:拼接字符串
ostringstream oss1;
oss1 << "姓名:" << "张三"
<< ",年龄:" << 20
<< ",成绩:" << 95.5;
string info = oss1.str(); // 通过str()获取字符串
cout << "拼接结果:" << info << endl;
// 2. 格式化数字转字符串
int num = 123;
double pi = 3.1415926;
ostringstream oss2;
oss2 << "整数转字符串:" << num << endl
<< "浮点数保留2位小数:" << fixed << setprecision(2) << pi;
cout << "\n格式化结果:\n" << oss2.str() << endl;
// 3. 清空字符串流(两种方式)
oss2.str(""); // 方式1:重置内部字符串
oss2.clear(); // 重置流状态(重要!否则之前的错误状态会保留)
oss2 << "重置后:" << hex << num; // 十六进制输出123
cout << "\n重置后结果:" << oss2.str() << endl;
return 0;
}
输入流用于将外部数据传输到程序中,C++ 中常用的输入流有cin(控制台输入)、ifstream(文件输入)和istringstream(字符串输入)。
输入流对象的构造与输出流类似,重点是文件打开模式和状态检查。
#include <iostream>
#include <fstream>
using namespace std;
int main() {
// 1. 控制台输入流(全局对象cin)
int num;
cout << "请输入一个整数:";
cin >> num;
cout << "你输入的是:" << num << endl;
// 2. 文件输入流构造方式1:默认构造+open()
ifstream ifs1;
ifs1.open("input1.txt"); // 默认模式ios::in
if (ifs1.is_open()) {
string line;
getline(ifs1, line); // 读取一行
cout << "ifs1读取内容:" << line << endl;
ifs1.close();
} else {
cerr << "ifs1打开文件失败!" << endl;
}
// 3. 文件输入流构造方式2:构造函数直接打开
ifstream ifs2("input2.txt", ios::in | ios::binary); // 二进制读模式
if (ifs2) { // 检查流状态
char buf[1024];
ifs2.read(buf, sizeof(buf)-1); // 留一个位置存结束符
buf[ifs2.gcount()] = '\0'; // gcount()返回实际读取的字节数
cout << "ifs2读取字节数:" << ifs2.gcount() << endl;
cout << "ifs2读取内容:" << buf << endl;
ifs2.close();
} else {
cerr << "ifs2打开文件失败!" << endl;
}
return 0;
}
>>是输入流的提取运算符,用于从输入流中读取数据,默认会跳过空白字符(空格、换行、制表符等)。
#include <iostream>
#include <string>
using namespace std;
int main() {
cout << "请输入姓名、年龄、身高(用空格分隔):";
string name;
int age;
double height;
// 提取运算符会自动跳过空白字符
cin >> name >> age >> height;
// 输出读取结果
cout << "\n你输入的信息:" << endl;
cout << "姓名:" << name << endl;
cout << "年龄:" << age << endl;
cout << "身高:" << height << "m" << endl;
// 注意:提取运算符遇到空白字符停止,适合读取结构化数据
// 如需读取含空格的字符串,需用getline()
cout << "\n请输入一句话(含空格):";
cin.ignore(); // 忽略之前输入留下的换行符
string sentence;
getline(cin, sentence); // 读取一行(含空格)
cout << "你输入的句子:" << sentence << endl;
return 0;
}
输入流操纵符用于控制输入格式,常用操纵符如下:
操纵符 | 功能 | 头文件 |
|---|---|---|
skipws | 跳过空白字符(默认) | <iostream> |
noskipws | 不跳过空白字符 | <iostream> |
hex/oct/dec | 设置整数输入进制 | <iostream> |
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
// 1. 进制转换输入
int num;
cout << "请输入一个十六进制数(如1A):";
cin >> hex >> num; // hex设置输入为十六进制
cout << "转换为十进制:" << dec << num << endl; // dec恢复十进制输出
// 2. noskipws:不跳过空白字符
char c1, c2;
cout << "\n请输入两个字符(用空格分隔):";
cin >> skipws >> c1; // 默认跳过空格
cin >> noskipws >> c2; // 不跳过空格(会读取空格)
cout << "c1:'" << c1 << "',ASCII:" << int(c1) << endl;
cout << "c2:'" << c2 << "',ASCII:" << int(c2) << endl;
// 3. 重置为默认状态
cin >> skipws;
return 0;
}
输入流提供了get()、getline()、read()等成员函数,用于更灵活的输入操作。
函数 | 功能 |
|---|---|
get(char& c) | 读取单个字符(包括空白) |
getline(char* buf, int n) | 读取一行到 buf,最多 n-1 个字符 |
read(char* buf, streamsize n) | 读取 n 个字节到 buf |
gcount() | 返回上次读取的字节数 |
tellg() | 返回当前读位置 |
seekg(pos) | 设置读位置 |
eof() | 判断是否到达文件末尾 |
fail() | 判断是否发生非致命错误 |
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
// 1. 控制台输入函数演示
cout << "请输入一个字符:";
char c;
cin.get(c); // 读取单个字符(包括空格、换行)
cout << "你输入的字符:'" << c << "',ASCII:" << int(c) << endl;
cin.ignore(); // 忽略残留的换行符
cout << "请输入一行话:";
char buf[100];
cin.getline(buf, 100); // 读取一行到缓冲区
cout << "你输入的内容:" << buf << endl;
// 2. 文件输入函数演示
ifstream ifs("input_func.txt");
if (!ifs) {
cerr << "文件打开失败!" << endl;
return 1;
}
// 读取文件内容
char file_buf[1024];
ifs.read(file_buf, sizeof(file_buf)-1); // 读取字节
streamsize bytes_read = ifs.gcount(); // 获取实际读取的字节数
file_buf[bytes_read] = '\0'; // 添加结束符
cout << "\n文件读取字节数:" << bytes_read << endl;
cout << "文件内容:\n" << file_buf << endl;
// 获取文件大小(移动到末尾再获取位置)
ifs.seekg(0, ios::end); // 移动到文件末尾
streampos file_size = ifs.tellg(); // 获取当前位置(即文件大小)
cout << "文件总大小:" << file_size << "字节" << endl;
ifs.close();
return 0;
}
istringstream用于从字符串中读取数据,可实现 "字符串解析" 功能,定义在<sstream>头文件中。
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
// 1. 解析结构化字符串
string data = "张三 20 95.5 男";
istringstream iss(data); // 用字符串初始化输入流
string name;
int age;
double score;
string gender;
// 从字符串流中提取数据,类似cin
iss >> name >> age >> score >> gender;
cout << "解析结果:" << endl;
cout << "姓名:" << name << endl;
cout << "年龄:" << age << endl;
cout << "成绩:" << score << endl;
cout << "性别:" << gender << endl;
// 2. 字符串转数字
string num_str = "12345";
istringstream num_iss(num_str);
int num;
num_iss >> num;
cout << "\n字符串\"" << num_str << "\"转整数:" << num << endl;
// 3. 处理CSV格式字符串
string csv = "2023,12,25";
istringstream csv_iss(csv);
int year, month, day;
char delim; // 用于接收分隔符','
csv_iss >> year >> delim >> month >> delim >> day;
cout << "\nCSV解析结果:" << year << "年" << month << "月" << day << "日" << endl;
return 0;
}
fstream是兼具输入和输出功能的流类,可同时进行文件的读写操作,需指定ios::in | ios::out模式。
模式组合 | 功能 | ||
|---|---|---|---|
`ios::in | ios::out` | 读写模式,文件必须存在 | |
`ios::in | ios::out | ios::trunc` | 读写模式,文件不存在则创建,存在则清空 |
`ios::in | ios::out | ios::app` | 读写模式,写操作追加到文件末尾 |
`ios::in | ios::out | ios::binary` | 二进制读写模式 |
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
// 创建并写入初始内容
ofstream ofs("io_stream.txt");
if (!ofs) {
cerr << "创建文件失败!" << endl;
return 1;
}
ofs << "初始内容:Hello World!\n这是第二行。" << endl;
ofs.close();
// 以读写模式打开文件
fstream fs("io_stream.txt", ios::in | ios::out);
if (!fs) {
cerr << "文件打开失败!" << endl;
return 1;
}
// 读取第一行内容
string first_line;
getline(fs, first_line);
cout << "读取第一行:" << first_line << endl;
// 移动到文件开头并写入新内容(覆盖原有内容)
fs.seekp(0, ios::beg); // 设置写位置到开头
fs << "修改后的第一行"; // 写入内容(长度不足会保留原内容剩余部分)
// 移动到文件末尾追加内容
fs.seekp(0, ios::end); // 设置写位置到末尾
fs << "\n这是追加的内容" << endl;
// 验证修改结果
fs.seekg(0, ios::beg); // 移动读位置到开头
cout << "\n文件完整内容:" << endl;
string line;
while (getline(fs, line)) { // 循环读取所有行
cout << line << endl;
}
fs.close();
return 0;
}
本实例基于文件流实现银行账户数据的持久化存储,将账户信息保存到文件中,下次运行时可读取恢复。
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <limits> // 新增:包含numeric_limits所需的头文件
using namespace std;
// 银行账户类
class BankAccount {
private:
string accountId; // 账号
string name; // 姓名
double balance; // 余额
public:
// 构造函数
BankAccount(string id = "", string n = "", double b = 0.0)
: accountId(id), name(n), balance(b) {}
// 存款
void deposit(double amount) {
if (amount > 0) {
balance += amount;
cout << "存款成功!存入金额:" << amount << endl;
} else {
cout << "存款金额必须为正数!" << endl;
}
}
// 取款
bool withdraw(double amount) {
if (amount <= 0) {
cout << "取款金额必须为正数!" << endl;
return false;
}
if (amount > balance) {
cout << "余额不足!当前余额:" << balance << endl;
return false;
}
balance -= amount;
cout << "取款成功!取出金额:" << amount << endl;
return true;
}
// 显示账户信息
void showInfo() const {
cout << "\n===== 账户信息 =====" << endl;
cout << "账号:" << accountId << endl;
cout << "姓名:" << name << endl;
cout << "余额:" << balance << "元" << endl;
cout << "====================" << endl;
}
// 保存账户信息到文件(友元函数)
friend ofstream& operator<<(ofstream& ofs, const BankAccount& acc) {
ofs << acc.accountId << endl;
ofs << acc.name << endl;
ofs << acc.balance << endl;
return ofs;
}
// 从文件读取账户信息
friend ifstream& operator>>(ifstream& ifs, BankAccount& acc) {
ifs >> acc.accountId;
ifs >> acc.name;
ifs >> acc.balance;
// 忽略行尾的换行符(需要#include <limits>)
ifs.ignore(numeric_limits<streamsize>::max(), '\n');
return ifs;
}
// 获取账号(用于查找)
string getAccountId() const { return accountId; }
};
// 账户管理类
class AccountManager {
private:
vector<BankAccount> accounts; // 账户集合
string filename; // 保存文件名称
public:
// 构造函数:指定保存文件
AccountManager(string fn) : filename(fn) {
loadAccounts(); // 初始化时加载账户
}
// 加载账户信息
void loadAccounts() {
ifstream ifs(filename);
if (!ifs) {
cout << "首次运行,未找到账户文件,将创建新文件。" << endl;
return;
}
BankAccount acc;
while (ifs >> acc) { // 循环读取所有账户
accounts.push_back(acc);
}
cout << "成功加载 " << accounts.size() << " 个账户信息。" << endl;
}
// 保存账户信息
void saveAccounts() {
ofstream ofs(filename);
if (!ofs) {
cerr << "保存账户失败!" << endl;
return;
}
for (const auto& acc : accounts) {
ofs << acc; // 使用重载的<<运算符
}
cout << "成功保存 " << accounts.size() << " 个账户信息。" << endl;
}
// 添加账户
void addAccount(const BankAccount& acc) {
accounts.push_back(acc);
saveAccounts(); // 立即保存
}
// 查找账户
BankAccount* findAccount(const string& id) {
for (auto& acc : accounts) {
if (acc.getAccountId() == id) {
return &acc;
}
}
return nullptr;
}
// 显示所有账户
void showAllAccounts() {
if (accounts.empty()) {
cout << "暂无账户信息!" << endl;
return;
}
cout << "\n===== 所有账户信息 =====" << endl;
for (const auto& acc : accounts) {
acc.showInfo();
}
}
};
// 主函数:菜单交互
int main() {
AccountManager manager("bank_accounts.txt");
int choice;
do {
cout << "\n===== 银行账户管理系统 =====" << endl;
cout << "1. 添加账户" << endl;
cout << "2. 查找账户" << endl;
cout << "3. 存款" << endl;
cout << "4. 取款" << endl;
cout << "5. 显示所有账户" << endl;
cout << "0. 退出" << endl;
cout << "请选择操作:";
cin >> choice;
switch (choice) {
case 1: {
string id, name;
double balance;
cout << "请输入账号:";
cin >> id;
cout << "请输入姓名:";
cin >> name;
cout << "请输入初始余额:";
cin >> balance;
manager.addAccount(BankAccount(id, name, balance));
break;
}
case 2: {
string id;
cout << "请输入要查找的账号:";
cin >> id;
BankAccount* acc = manager.findAccount(id);
if (acc) {
acc->showInfo();
} else {
cout << "未找到账号为 " << id << " 的账户!" << endl;
}
break;
}
case 3: {
string id;
double amount;
cout << "请输入账号:";
cin >> id;
BankAccount* acc = manager.findAccount(id);
if (acc) {
cout << "请输入存款金额:";
cin >> amount;
acc->deposit(amount);
manager.saveAccounts(); // 保存修改
} else {
cout << "未找到账号为 " << id << " 的账户!" << endl;
}
break;
}
case 4: {
string id;
double amount;
cout << "请输入账号:";
cin >> id;
BankAccount* acc = manager.findAccount(id);
if (acc) {
cout << "请输入取款金额:";
cin >> amount;
if (acc->withdraw(amount)) {
manager.saveAccounts(); // 保存修改
}
} else {
cout << "未找到账号为 " << id << " 的账户!" << endl;
}
break;
}
case 5:
manager.showAllAccounts();
break;
case 0:
cout << "谢谢使用,再见!" << endl;
break;
default:
cout << "无效选择,请重新输入!" << endl;
}
} while (choice != 0);
return 0;
}
C++ 支持宽字符(wchar_t)用于处理 Unicode 字符,对应的宽流类用于宽字符输入输出,核心宽流类如下:
窄流类 | 宽流类 | 功能 |
|---|---|---|
cin | wcin | 宽字符控制台输入 |
cout | wcout | 宽字符控制台输出 |
ifstream | wifstream | 宽字符文件输入 |
ofstream | wofstream | 宽字符文件输出 |
stringstream | wstringstream | 宽字符串流 |
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <locale> // 用于本地化设置
using namespace std;
int main() {
// 设置本地化(支持中文等宽字符)
setlocale(LC_ALL, ""); // Windows使用"chs",Linux/macOS使用"zh_CN.UTF-8"
// 1. 宽字符控制台输出
wcout << L"===== 宽字符控制台输出 =====" << endl;
wchar_t wch = L'中'; // 宽字符用L前缀
wstring wstr = L"宽字符串:Hello 世界!"; // 宽字符串用L前缀
wcout << L"单个宽字符:" << wch << endl;
wcout << L"宽字符串:" << wstr << endl << endl;
// 2. 宽字符文件操作
wofstream wofs("wide_char.txt");
if (wofs) {
wofs << L"写入宽字符文件:你好,C++宽流!" << endl;
wofs << L"数字:123,字符:π" << endl; // 可写入特殊字符
wofs.close();
wcout << L"宽字符文件写入完成!" << endl;
} else {
wcerr << L"宽字符文件打开失败!" << endl;
}
// 读取宽字符文件
wifstream wifs("wide_char.txt");
if (wifs) {
wcout << endl << L"读取宽字符文件内容:" << endl;
wstring wline;
while (getline(wifs, wline)) { // 宽字符getline
wcout << wline << endl;
}
wifs.close();
}
// 3. 宽字符串流
wstringstream wss;
wss << L"宽字符串流拼接:" << wstr << L" 长度:" << wstr.size();
wcout << endl << L"宽字符串流结果:" << wss.str() << endl;
return 0;
} 对象串行化(Serialization)是将对象状态转换为可存储或传输的格式(如二进制)的过程,便于对象持久化或网络传输。C++ 中可通过write()和read()实现简单的对象串行化。
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// 可串行化的学生类
class Student {
private:
int id;
string name; // 注意:string内部有指针,需特殊处理
float score;
public:
Student(int i = 0, string n = "", float s = 0.0f)
: id(i), name(n), score(s) {}
// 显示信息
void show() const {
cout << "学号:" << id << ",姓名:" << name << ",成绩:" << score << endl;
}
// 串行化(保存对象到文件)
void serialize(ofstream& ofs) const {
// 1. 写入基本类型
ofs.write(reinterpret_cast<const char*>(&id), sizeof(id));
// 2. 写入string:先写长度,再写内容
size_t name_len = name.size();
ofs.write(reinterpret_cast<const char*>(&name_len), sizeof(name_len));
ofs.write(name.c_str(), name_len); // 写入字符串内容
// 3. 写入基本类型
ofs.write(reinterpret_cast<const char*>(&score), sizeof(score));
}
// 反串行化(从文件恢复对象)
void deserialize(ifstream& ifs) {
// 1. 读取基本类型
ifs.read(reinterpret_cast<char*>(&id), sizeof(id));
// 2. 读取string:先读长度,再读内容
size_t name_len;
ifs.read(reinterpret_cast<char*>(&name_len), sizeof(name_len));
char* name_buf = new char[name_len + 1];
ifs.read(name_buf, name_len);
name_buf[name_len] = '\0';
name = name_buf;
delete[] name_buf; // 释放临时缓冲区
// 3. 读取基本类型
ifs.read(reinterpret_cast<char*>(&score), sizeof(score));
}
};
int main() {
// 创建对象
Student s1(1001, "张三", 95.5f);
Student s2(1002, "李四", 88.0f);
cout << "原始对象:" << endl;
s1.show();
s2.show();
// 串行化对象到文件
ofstream ofs("students_serialize.dat", ios::binary);
if (ofs) {
s1.serialize(ofs);
s2.serialize(ofs);
ofs.close();
cout << "\n对象串行化完成!" << endl;
} else {
cerr << "文件打开失败!" << endl;
return 1;
}
// 反串行化恢复对象
Student s3, s4;
ifstream ifs("students_serialize.dat", ios::binary);
if (ifs) {
s3.deserialize(ifs);
s4.deserialize(ifs);
ifs.close();
cout << "\n反串行化恢复对象:" << endl;
s3.show();
s4.show();
} else {
cerr << "文件打开失败!" << endl;
return 1;
}
return 0;
}
本章详细介绍了 C++ 流类库与输入输出的核心知识,主要包括:
ios、istream、ostream等核心类)cout控制台输出、ofstream文件输出、ostringstream字符串输出,以及格式控制cin控制台输入、ifstream文件输入、istringstream字符串输入,以及灵活的读取函数fstream实现文件的同时读写掌握流类库的使用,能让你灵活处理各种输入输出场景,从简单的控制台交互到复杂的文件操作和对象持久化,为实际项目开发打下坚实基础。