好的,我们来详细讲解 C++ 中的 IO 流系统,包括标准 IO、文件 IO 和字符串 IO,并提供实战代码示例。
C++ IO 流详解
C++ 的输入/输出系统基于流的概念。流是一个抽象,代表数据从一个源(如键盘、文件、内存)流向一个目标(如屏幕、文件、内存)的序列。iostream 库提供了处理这些流的类和函数。
主要分为三大类:
- 标准 IO:处理标准输入(键盘)和标准输出(屏幕/控制台)。
- 文件 IO:处理磁盘文件的读写。
- 字符串 IO:处理内存中的字符串,就像处理文件或控制台一样。
核心类库:
<iostream>:包含标准输入输出对象 (cin,cout,cerr,clog)。<fstream>:包含文件流类 (ifstream,ofstream,fstream)。<sstream>:包含字符串流类 (istringstream,ostringstream,stringstream)。
所有流类都继承自基类 ios_base 和 ios,它们定义了流的通用状态和格式化标志。
1. 标准 IO
- 对象:
cin:istream对象,绑定到标准输入(通常是键盘)。cout:ostream对象,绑定到标准输出(通常是屏幕)。cerr:ostream对象,绑定到标准错误输出(无缓冲,立即显示错误信息)。clog:ostream对象,绑定到标准日志输出(有缓冲,用于记录日志)。
- 基本操作:
- 输入 (
>>提取运算符): 从流中读取数据到变量。它会跳过前导空白字符(空格、制表符、换行符)。 - 输出 (
<<插入运算符): 将数据插入到输出流。
- 格式化: 可以使用操纵符(如
std::endl,std::setw,std::setprecision,std::fixed,std::showpoint,std::hex) 或ios成员函数(如setf,precision,width) 来控制输出的格式。 - 状态检查: 使用成员函数
good(),eof(),fail(),bad()检查流的状态。clear()可以清除错误状态。 - 实战示例:
#include <iostream> #include <iomanip> // 用于操纵符如 setw, setprecision int main() { int num; double pi = 3.1415926535; char ch; // 输入整数 std::cout << "请输入一个整数: "; std::cin >> num; if (std::cin.fail()) { std::cerr << "输入错误!请输入有效的整数。" << std::endl; std::cin.clear(); // 清除错误状态 std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 忽略错误输入行 return 1; } // 输出整数和格式化后的浮点数 std::cout << "你输入的整数是: " << num << std::endl; std::cout << "Pi 的值: " << std::setprecision(4) << std::fixed << pi << std::endl; // 输入字符 (注意 >> 会跳过空格) std::cout << "请输入一个字符: "; std::cin >> ch; // 如果缓冲区有残留的换行符,这里可能不会等待输入 std::cout << "你输入的字符是: " << ch << std::endl; // 读取一行 (包括空格) std::cout << "请输入一行文本: "; std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 清除之前的输入缓冲区 std::string line; std::getline(std::cin, line); // 使用 getline 读取整行 std::cout << "你输入的文本是: " << line << std::endl; return 0; }
2. 文件 IO
- 类:
ifstream: 输入文件流,用于从文件读取数据。ofstream: 输出文件流,用于向文件写入数据。fstream: 文件流,可同时用于输入和输出(读写)。
- 基本步骤:
- 打开文件: 创建流对象并关联到文件名。可以在构造函数中指定文件名和打开模式,或者先创建对象再用
open()成员函数打开。 - 检查是否打开成功: 使用
is_open()成员函数。 - 读写数据: 使用
>>,<<,getline()等操作符和函数,与标准 IO 类似。 - 关闭文件: 使用
close()成员函数。对象析构时也会自动关闭,但显式关闭是好习惯。
- 打开模式 (ios::openmode): 使用位或
|组合。
ios::in: 打开用于输入(读)。ios::out: 打开用于输出(写)。如果文件存在,默认会截断文件(清空内容)。使用ios::app或ios::ate避免。ios::app: 追加模式,所有写入都追加到文件末尾。ios::ate: 打开后定位到文件末尾,但写入位置可以移动。ios::trunc: 如果文件存在则截断(清空)。ios::binary: 以二进制模式打开文件,避免字符转换(如换行符处理)。
- 实战示例 (文本文件读写):
#include <iostream> #include <fstream> #include <string> int main() { // 写入文件 (覆盖模式) std::ofstream outfile("data.txt"); // 默认模式: ios::out | ios::trunc if (!outfile.is_open()) { std::cerr << "打开文件 data.txt 用于写入失败!" << std::endl; return 1; } outfile << "Hello, File IO!" << std::endl; outfile << "This is a test line." << std::endl; outfile << "Writing numbers: " << 42 << std::endl; outfile.close(); // 关闭文件 // 读取文件 std::ifstream infile("data.txt"); if (!infile.is_open()) { std::cerr << "打开文件 data.txt 用于读取失败!" << std::endl; return 1; } std::string line; std::cout << "文件内容:" << std::endl; while (std::getline(infile, line)) { std::cout << line << std::endl; } infile.close(); // 追加模式写入 std::ofstream appfile("data.txt", std::ios::app); // 追加模式 if (appfile.is_open()) { appfile << "This line is appended." << std::endl; appfile.close(); } return 0; }
- 实战示例 (二进制文件读写): 使用
read()和write()成员函数。
#include <iostream> #include <fstream> struct Person { char name[50]; int age; double height; }; int main() { Person p = {"Alice", 30, 1.75}; // 写二进制文件 std::ofstream b_outfile("person.dat", std::ios::binary); if (b_outfile.is_open()) { b_outfile.write(reinterpret_cast<char*>(&p), sizeof(Person)); b_outfile.close(); } // 读二进制文件 Person p_read; std::ifstream b_infile("person.dat", std::ios::binary); if (b_infile.is_open()) { b_infile.read(reinterpret_cast<char*>(&p_read), sizeof(Person)); b_infile.close(); std::cout << "Name: " << p_read.name << std::endl; std::cout << "Age: " << p_read.age << std::endl; std::cout << "Height: " << p_read.height << std::endl; } return 0; }
3. 字符串 IO
- 类:
istringstream: 输入字符串流,用于从字符串读取数据。ostringstream: 输出字符串流,用于向字符串写入数据。stringstream: 字符串流,可同时用于输入和输出。
- 用途:
- 格式化解析: 将包含多种类型数据的字符串分解成单独的变量。
- 格式化构造: 将不同类型的数据格式化为一个字符串。
- 内存中数据处理: 像操作文件或控制台一样操作字符串。
- 基本操作: 与标准 IO (
cin,cout) 和文件 IO 使用相同的>>,<<,getline(),str()等操作符和成员函数。 - 获取/设置字符串: 使用
str()成员函数获取或设置底层字符串对象。http://fhqgpmuxd.cn/article/20260224/272811.shtm
http://fhqgpmuxd.cn/article/20260224/272812.shtm
http://fhqgpmuxd.cn/article/20260224/272813.shtm
http://fhqgpmuxd.cn/article/20260224/272814.shtm
http://fhqgpmuxd.cn/article/20260224/272815.shtm
http://fhqgpmuxd.cn/article/20260224/272816.shtm
http://fhqgpmuxd.cn/article/20260224/272817.shtm
http://fhqgpmuxd.cn/article/20260224/272818.shtm
http://fhqgpmuxd.cn/article/20260224/272819.shtm
- 实战示例 (字符串解析):
#include <iostream> #include <sstream> #include <string> int main() { std::string data = "John Doe 30 1.85"; std::istringstream iss(data); std::string firstname, lastname; int age; double height; iss >> firstname >> lastname >> age >> height; std::cout << "First Name: " << firstname << std::endl; std::cout << "Last Name: " << lastname << std::endl; std::cout << "Age: " << age << std::endl; std::cout << "Height: " << height << std::endl; return 0; }
- 实战示例 (字符串格式化):
#include <iostream> #include <sstream> #include <string> int main() { std::ostringstream oss; int num = 123; double value = 45.67; std::string text = "Formatted"; oss << text << " output: Number=" << num << ", Value=" << value; std::string result = oss.str(); // 获取格式化后的字符串 std::cout << result << std::endl; // 输出: Formatted output: Number=123, Value=45.67 return 0; }
- 实战示例 (字符串流读写):
#include <iostream> #include <sstream> #include <string> int main() { std::stringstream ss; // 写入到字符串流 ss << "Initial content. "; ss << 100 << " "; ss << 3.14; // 从字符串流读取 std::string part; int num; double pi; ss >> part; // 读取到空格 std::cout << "Part1: " << part << std::endl; // 输出: Initial ss >> part; // 继续读取下一个单词 std::cout << "Part2: " << part << std::endl; // 输出: content. ss >> num; std::cout << "Number: " << num << std::endl; // 输出: 100 ss >> pi; std::cout << "Pi: " << pi << std::endl; // 输出: 3.14 return 0; }
总结:
- 标准 IO (
cin,cout): 用于与控制台交互。注意输入错误处理和缓冲区管理。 - 文件 IO (
ifstream,ofstream,fstream): 用于持久化存储。注意打开模式(文本/二进制、读/写/追加)和文件路径。 - 字符串 IO (
istringstream,ostringstream,stringstream): 用于内存中字符串的格式化和解析,非常灵活。
C++ IO 流提供了强大而统一的接口来处理各种输入输出需求。理解流的状态、格式化控制以及不同流类的特性和使用场景是高效使用 C++ IO 的关键。