第8章:IO库(IO Library)
一、导读
1.1 本章学习目标
第8章介绍C++的IO库。本章核心目标:
- 掌握标准IO:cin、cout、cerr的使用
- 学会文件IO:ifstream、ofstream、fstream
- 理解字符串流:istringstream、ostringstream
- 掌握IO状态管理:good()、fail()、eof()、bad()
- 学会格式化输出:setw、setprecision等
1.2 为什么本章如此重要
IO是程序与外部世界交互的通道。C++的IO库是面向对象的,支持类型安全的操作,比C的stdio更安全、更灵活。
1.3 核心问题引导
cin/cout和printf/scanf有什么本质区别?
文件打开失败时如何检测?
字符串流有什么实际用途?
IO状态标志在什么时候会改变?
二、核心概念详解
8.1 标准IO
cpp
#include <iostream>
#include <string>
int main() {
// 标准输出
std::cout << "Hello, World!" << std::endl;
std::cout << "The answer is " << 42 << std::endl;
// 标准输入
int age;
std::string name;
std::cout << "Enter name and age: ";
std::cin >> name >> age;
std::cout << "Hello, " << name << "! Age: " << age << std::endl;
// 读取整行
std::string line;
std::cout << "Enter a sentence: ";
std::getline(std::cin, line);
std::cout << "You said: " << line << std::endl;
// 标准错误
std::cerr << "Error: something went wrong!" << std::endl;
std::clog << "Log: this is a log message" << std::endl;
return 0;
}8.2 文件IO
cpp
#include <iostream>
#include <fstream>
#include <string>
int main() {
// 写入文件
std::ofstream outfile("test.txt");
if (!outfile) {
std::cerr << "Error opening file for writing" << std::endl;
return 1;
}
outfile << "Hello, File!" << std::endl;
outfile << "Line 2: " << 42 << std::endl;
outfile.close();
// 读取文件
std::ifstream infile("test.txt");
if (!infile) {
std::cerr << "Error opening file for reading" << std::endl;
return 1;
}
std::string line;
while (std::getline(infile, line)) {
std::cout << line << std::endl;
}
infile.close();
// 追加模式
std::ofstream appfile("test.txt", std::ios::app);
appfile << "Appended line" << std::endl;
appfile.close();
// 读写模式
std::fstream iofile("test.txt", std::ios::in | std::ios::out);
if (iofile) {
std::string first_line;
std::getline(iofile, first_line);
std::cout << "First line: " << first_line << std::endl;
iofile.close();
}
return 0;
}8.3 字符串流
cpp
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
int main() {
// ostringstream:构建字符串
std::ostringstream oss;
oss << "Name: Alice, Age: " << 20
<< ", Score: " << std::fixed << std::setprecision(2) << 95.5;
std::string result = oss.str();
std::cout << result << std::endl;
// istringstream:解析字符串
std::istringstream iss("123 45.67 hello");
int num;
double d;
std::string str;
iss >> num >> d >> str;
std::cout << num << ", " << d << ", " << str << std::endl;
// 格式化输出
double pi = 3.14159265358979;
std::cout << std::setw(15) << std::setprecision(4) << pi << std::endl;
std::cout << std::setw(15) << std::left << pi << std::endl;
std::cout << std::setw(15) << std::right << pi << std::endl;
// 进制转换
int value = 255;
std::cout << "Decimal: " << std::dec << value << std::endl;
std::cout << "Hex: " << std::hex << value << std::endl;
std::cout << "Octal: " << std::oct << value << std::endl;
return 0;
}8.4 IO状态管理
cpp
#include <iostream>
#include <fstream>
int main() {
std::ifstream file("test.txt");
// 检查IO状态
if (file.good()) {
std::cout << "Stream is in good state" << std::endl;
}
// 逐词读取
std::string word;
while (file >> word) {
std::cout << word << " ";
}
// 检查为什么循环结束
if (file.eof()) {
std::cout << "\nReached end of file" << std::endl;
}
if (file.fail()) {
std::cout << "A format error occurred" << std::endl;
}
if (file.bad()) {
std::cout << "A serious I/O error occurred" << std::endl;
}
// 清除错误状态
file.clear();
file.close();
return 0;
}三、实战案例
3.1 文件复制程序
cpp
#include <iostream>
#include <fstream>
#include <string>
bool copyFile(const std::string &src, const std::string &dst) {
std::ifstream infile(src, std::ios::binary);
if (!infile) {
std::cerr << "Cannot open source file: " << src << std::endl;
return false;
}
std::ofstream outfile(dst, std::ios::binary);
if (!outfile) {
std::cerr << "Cannot open destination file: " << dst << std::endl;
return false;
}
char buffer[4096];
while (infile.read(buffer, sizeof(buffer))) {
outfile.write(buffer, infile.gcount());
}
// 写入剩余数据
outfile.write(buffer, infile.gcount());
infile.close();
outfile.close();
return true;
}
int main(int argc, char *argv[]) {
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " source destination" << std::endl;
return 1;
}
if (copyFile(argv[1], argv[2])) {
std::cout << "File copied successfully" << std::endl;
}
return 0;
}3.2 简单的CSV解析器
cpp
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
struct Record {
std::string name;
int age;
std::string city;
};
std::vector<Record> readCSV(const std::string &filename) {
std::vector<Record> records;
std::ifstream file(filename);
std::string line;
std::getline(file, line); // 跳过标题行
while (std::getline(file, line)) {
std::istringstream iss(line);
Record r;
std::string token;
std::getline(iss, token, ',');
r.name = token;
std::getline(iss, token, ',');
r.age = std::stoi(token);
std::getline(iss, token, ',');
r.city = token;
records.push_back(r);
}
return records;
}
int main() {
// 创建测试CSV
std::ofstream csv("data.csv");
csv << "name,age,city" << std::endl;
csv << "Alice,20,Beijing" << std::endl;
csv << "Bob,25,Shanghai" << std::endl;
csv << "Charlie,30,Guangzhou" << std::endl;
csv.close();
auto records = readCSV("data.csv");
for (const auto &r : records) {
std::cout << r.name << ", " << r.age << ", " << r.city << std::endl;
}
return 0;
}四、本章小结
第8章介绍了C++的IO库:标准IO(cin/cout/cerr)、文件IO(ifstream/ofstream/fstream)、字符串流(istringstream/ostringstream)、IO状态管理、格式化输出。
五、思考与练习
思考题
cout和cerr有什么区别?什么时候用cerr?
文件打开失败时如何检测和处理?
字符串流在什么场景下特别有用?
二进制模式和文本模式有什么区别?
编程练习
实现一个简单的文本搜索工具,在文件中查找关键词。
编写程序读取JSON文件并解析。
实现一个日志系统,支持不同级别的日志输出。