| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- /*
- * ============================================================
- * C++语言文件读写示例 (cpp_file_io.cpp)
- * ============================================================
- *
- * C++ 使用 <fstream> 头文件中提供的流(stream)类来操作文件,
- * 常用的三个类:
- * std::ifstream —— 输入文件流(input file stream),用于"读"
- * std::ofstream —— 输出文件流(output file stream),用于"写"
- * std::fstream —— 输入输出文件流,既能读也能写
- *
- * 这些类都继承自 std::istream / std::ostream,因此可以像操作
- * std::cin / std::cout 一样,使用 << 和 >> 运算符读写文件,
- * 也可以用 getline() 按行读取。
- *
- * 打开模式(第二个参数),用 std::ios 里的枚举值组合(用 | 连接):
- * std::ios::in 只读
- * std::ios::out 只写
- * std::ios::app 追加
- * std::ios::trunc 打开时清空文件
- * std::ios::binary 二进制模式(不做文本转换)
- * std::ios::ate 打开后立即定位到文件末尾
- *
- * 与C语言最大的不同点(RAII机制):
- * ifstream/ofstream 是"资源获取即初始化"(RAII)的对象,
- * 当它离开作用域(比如函数结束、{}代码块结束)时,
- * 析构函数会自动调用 close(),把缓冲区数据刷新到磁盘,
- * 不需要像C语言那样手动调用 fclose(),从而避免忘记关闭
- * 文件导致的资源泄漏问题。
- *
- * 特点总结:
- * 1. 面向对象,类型安全:可以直接用 << 写入 int/double/string等,
- * 不需要像C那样写格式化字符串"%d"。
- * 2. 自动管理资源(RAII),无需手动close,异常安全性更好。
- * 3. 可以用异常(exceptions)机制处理错误,也可以用状态位(good/fail/eof)判断。
- * 4. 相比C的stdio,部分场景下性能略低(多了一层抽象),但差距通常很小,
- * 且可以通过 sync_with_stdio(false) 等方式优化。
- * ============================================================
- */
- #include <iostream> // std::cout, std::cerr
- #include <fstream> // std::ifstream, std::ofstream, std::fstream
- #include <string> // std::string, std::getline
- #include <vector> // std::vector 用于存放读取到的数据
- #include <sstream> // std::istringstream 用于按逗号分割字符串
- /* 定义一个结构体,与C版本对应,用于演示二进制读写 */
- struct Student {
- int id;
- char name[32]; // 为了让二进制布局和C版本一致,这里用char数组而不是std::string
- double score;
- };
- int main()
- {
- const std::string text_file = "cpp_demo.txt";
- const std::string binary_file = "cpp_demo.bin";
- /* ---------------------------------------------------------
- * 第一部分:文本文件的写入与读取
- * --------------------------------------------------------- */
- std::cout << "===== [C++] 文本文件读写演示 =====\n";
- /* 1. 创建 ofstream 对象即可"打开"文件用于写入
- * 默认模式是 std::ios::out,若省略第二参数也可以。
- * 与C的"w"模式一样:文件不存在则创建,存在则清空。
- */
- {
- std::ofstream ofs(text_file); // 等价于 ofstream ofs(text_file, std::ios::out);
- if (!ofs.is_open()) {
- // is_open() 判断文件是否打开成功,类似C语言判断 fp == NULL
- std::cerr << "打开文件写入失败: " << text_file << std::endl;
- return 1;
- }
- /* 2. 直接使用 << 运算符写入,像 std::cout 一样自然,无需格式化字符串 */
- ofs << "Hello from C++!" << "\n";
- ofs << 1 << "," << "Alice" << "," << 95.5 << "\n";
- ofs << 2 << "," << "Bob" << "," << 88.0 << "\n";
- std::cout << "已写入文件: " << text_file << std::endl;
- /* 3. ofs 在这个花括号 {} 结束时会自动析构,自动调用close()刷新并关闭文件,
- * 不需要像C语言那样手动 fclose()!这就是RAII的好处。
- */
- }
- /* 4. 重新打开文件用于读取,使用 ifstream */
- {
- std::ifstream ifs(text_file);
- if (!ifs.is_open()) {
- std::cerr << "打开文件读取失败: " << text_file << std::endl;
- return 1;
- }
- /* 5. 使用 std::getline 按行读取到 std::string 中,
- * 比C的fgets更安全(不需要担心缓冲区大小、不会保留换行符)。
- */
- std::string line;
- std::cout << "--- 按行读取内容 ---\n";
- while (std::getline(ifs, line)) {
- std::cout << "读到一行: " << line << std::endl;
- }
- // ifs 离开作用域自动关闭
- }
- /* 6. 使用 istringstream 解析逗号分隔的结构化数据(比C的fscanf更安全灵活) */
- {
- std::ifstream ifs(text_file);
- std::string line;
- std::getline(ifs, line); // 跳过第一行 "Hello from C++!"
- std::cout << "--- 使用istringstream解析结构化数据 ---\n";
- while (std::getline(ifs, line)) {
- std::istringstream iss(line);
- std::string id_str, name, score_str;
- if (std::getline(iss, id_str, ',') &&
- std::getline(iss, name, ',') &&
- std::getline(iss, score_str)) {
- int id = std::stoi(id_str);
- double score = std::stod(score_str);
- std::cout << "解析结果: id=" << id
- << ", name=" << name
- << ", score=" << score << std::endl;
- }
- }
- }
- /* ---------------------------------------------------------
- * 第二部分:二进制文件的写入与读取
- * --------------------------------------------------------- */
- std::cout << "\n===== [C++] 二进制文件读写演示 =====\n";
- std::vector<Student> students_out = {
- {1, "Alice", 95.5},
- {2, "Bob", 88.0}
- };
- /* 1. 以二进制写模式打开:std::ios::out | std::ios::binary */
- {
- std::ofstream ofs(binary_file, std::ios::out | std::ios::binary);
- if (!ofs.is_open()) {
- std::cerr << "打开二进制文件写入失败" << std::endl;
- return 1;
- }
- /* 2. write(数据地址(需转成char*), 字节数)
- * reinterpret_cast<const char*> 把任意类型指针转换为 char* 字节流,
- * 这是C++里进行二进制IO的标准写法。
- */
- ofs.write(reinterpret_cast<const char*>(students_out.data()),
- sizeof(Student) * students_out.size());
- std::cout << "写入了 " << students_out.size() << " 条学生记录\n";
- }
- /* 3. 以二进制读模式打开并读回 */
- {
- std::ifstream ifs(binary_file, std::ios::in | std::ios::binary);
- if (!ifs.is_open()) {
- std::cerr << "打开二进制文件读取失败" << std::endl;
- return 1;
- }
- std::vector<Student> students_in(2);
- ifs.read(reinterpret_cast<char*>(students_in.data()),
- sizeof(Student) * students_in.size());
- // gcount() 返回上一次read实际读取到的字节数,可用于校验是否读满
- std::streamsize actually_read = ifs.gcount();
- size_t record_count = actually_read / sizeof(Student);
- std::cout << "读取了 " << record_count << " 条学生记录:\n";
- for (size_t i = 0; i < record_count; i++) {
- std::cout << " id=" << students_in[i].id
- << ", name=" << students_in[i].name
- << ", score=" << students_in[i].score << std::endl;
- }
- }
- /* ---------------------------------------------------------
- * 第三部分:追加写入演示 (std::ios::app)
- * --------------------------------------------------------- */
- std::cout << "\n===== [C++] 追加写入演示 =====\n";
- {
- std::ofstream ofs(text_file, std::ios::app); // 追加模式,不清空原内容
- if (ofs.is_open()) {
- ofs << 3 << "," << "Charlie" << "," << 77.0 << "\n";
- std::cout << "已追加一行到 " << text_file << std::endl;
- }
- }
- /* ---------------------------------------------------------
- * 第四部分:使用fstream同时读写同一个文件(C++特有的便利类)
- * --------------------------------------------------------- */
- std::cout << "\n===== [C++] fstream 读写同一文件演示 =====\n";
- {
- // in | out 表示既能读也能写;文件必须已存在(不加trunc就不会清空)
- std::fstream fs(text_file, std::ios::in | std::ios::out);
- if (fs.is_open()) {
- std::string first;
- std::getline(fs, first);
- std::cout << "fstream读到第一行: " << first << std::endl;
- // 还可以继续用 fs << ... 写入,实现同一个流对象读写混合操作
- }
- }
- std::cout << "\nC++语言文件读写演示结束。\n";
- return 0;
- }
|