1
0

cpp_file_io.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * ============================================================
  3. * C++语言文件读写示例 (cpp_file_io.cpp)
  4. * ============================================================
  5. *
  6. * C++ 使用 <fstream> 头文件中提供的流(stream)类来操作文件,
  7. * 常用的三个类:
  8. * std::ifstream —— 输入文件流(input file stream),用于"读"
  9. * std::ofstream —— 输出文件流(output file stream),用于"写"
  10. * std::fstream —— 输入输出文件流,既能读也能写
  11. *
  12. * 这些类都继承自 std::istream / std::ostream,因此可以像操作
  13. * std::cin / std::cout 一样,使用 << 和 >> 运算符读写文件,
  14. * 也可以用 getline() 按行读取。
  15. *
  16. * 打开模式(第二个参数),用 std::ios 里的枚举值组合(用 | 连接):
  17. * std::ios::in 只读
  18. * std::ios::out 只写
  19. * std::ios::app 追加
  20. * std::ios::trunc 打开时清空文件
  21. * std::ios::binary 二进制模式(不做文本转换)
  22. * std::ios::ate 打开后立即定位到文件末尾
  23. *
  24. * 与C语言最大的不同点(RAII机制):
  25. * ifstream/ofstream 是"资源获取即初始化"(RAII)的对象,
  26. * 当它离开作用域(比如函数结束、{}代码块结束)时,
  27. * 析构函数会自动调用 close(),把缓冲区数据刷新到磁盘,
  28. * 不需要像C语言那样手动调用 fclose(),从而避免忘记关闭
  29. * 文件导致的资源泄漏问题。
  30. *
  31. * 特点总结:
  32. * 1. 面向对象,类型安全:可以直接用 << 写入 int/double/string等,
  33. * 不需要像C那样写格式化字符串"%d"。
  34. * 2. 自动管理资源(RAII),无需手动close,异常安全性更好。
  35. * 3. 可以用异常(exceptions)机制处理错误,也可以用状态位(good/fail/eof)判断。
  36. * 4. 相比C的stdio,部分场景下性能略低(多了一层抽象),但差距通常很小,
  37. * 且可以通过 sync_with_stdio(false) 等方式优化。
  38. * ============================================================
  39. */
  40. #include <iostream> // std::cout, std::cerr
  41. #include <fstream> // std::ifstream, std::ofstream, std::fstream
  42. #include <string> // std::string, std::getline
  43. #include <vector> // std::vector 用于存放读取到的数据
  44. #include <sstream> // std::istringstream 用于按逗号分割字符串
  45. /* 定义一个结构体,与C版本对应,用于演示二进制读写 */
  46. struct Student {
  47. int id;
  48. char name[32]; // 为了让二进制布局和C版本一致,这里用char数组而不是std::string
  49. double score;
  50. };
  51. int main()
  52. {
  53. const std::string text_file = "cpp_demo.txt";
  54. const std::string binary_file = "cpp_demo.bin";
  55. /* ---------------------------------------------------------
  56. * 第一部分:文本文件的写入与读取
  57. * --------------------------------------------------------- */
  58. std::cout << "===== [C++] 文本文件读写演示 =====\n";
  59. /* 1. 创建 ofstream 对象即可"打开"文件用于写入
  60. * 默认模式是 std::ios::out,若省略第二参数也可以。
  61. * 与C的"w"模式一样:文件不存在则创建,存在则清空。
  62. */
  63. {
  64. std::ofstream ofs(text_file); // 等价于 ofstream ofs(text_file, std::ios::out);
  65. if (!ofs.is_open()) {
  66. // is_open() 判断文件是否打开成功,类似C语言判断 fp == NULL
  67. std::cerr << "打开文件写入失败: " << text_file << std::endl;
  68. return 1;
  69. }
  70. /* 2. 直接使用 << 运算符写入,像 std::cout 一样自然,无需格式化字符串 */
  71. ofs << "Hello from C++!" << "\n";
  72. ofs << 1 << "," << "Alice" << "," << 95.5 << "\n";
  73. ofs << 2 << "," << "Bob" << "," << 88.0 << "\n";
  74. std::cout << "已写入文件: " << text_file << std::endl;
  75. /* 3. ofs 在这个花括号 {} 结束时会自动析构,自动调用close()刷新并关闭文件,
  76. * 不需要像C语言那样手动 fclose()!这就是RAII的好处。
  77. */
  78. }
  79. /* 4. 重新打开文件用于读取,使用 ifstream */
  80. {
  81. std::ifstream ifs(text_file);
  82. if (!ifs.is_open()) {
  83. std::cerr << "打开文件读取失败: " << text_file << std::endl;
  84. return 1;
  85. }
  86. /* 5. 使用 std::getline 按行读取到 std::string 中,
  87. * 比C的fgets更安全(不需要担心缓冲区大小、不会保留换行符)。
  88. */
  89. std::string line;
  90. std::cout << "--- 按行读取内容 ---\n";
  91. while (std::getline(ifs, line)) {
  92. std::cout << "读到一行: " << line << std::endl;
  93. }
  94. // ifs 离开作用域自动关闭
  95. }
  96. /* 6. 使用 istringstream 解析逗号分隔的结构化数据(比C的fscanf更安全灵活) */
  97. {
  98. std::ifstream ifs(text_file);
  99. std::string line;
  100. std::getline(ifs, line); // 跳过第一行 "Hello from C++!"
  101. std::cout << "--- 使用istringstream解析结构化数据 ---\n";
  102. while (std::getline(ifs, line)) {
  103. std::istringstream iss(line);
  104. std::string id_str, name, score_str;
  105. if (std::getline(iss, id_str, ',') &&
  106. std::getline(iss, name, ',') &&
  107. std::getline(iss, score_str)) {
  108. int id = std::stoi(id_str);
  109. double score = std::stod(score_str);
  110. std::cout << "解析结果: id=" << id
  111. << ", name=" << name
  112. << ", score=" << score << std::endl;
  113. }
  114. }
  115. }
  116. /* ---------------------------------------------------------
  117. * 第二部分:二进制文件的写入与读取
  118. * --------------------------------------------------------- */
  119. std::cout << "\n===== [C++] 二进制文件读写演示 =====\n";
  120. std::vector<Student> students_out = {
  121. {1, "Alice", 95.5},
  122. {2, "Bob", 88.0}
  123. };
  124. /* 1. 以二进制写模式打开:std::ios::out | std::ios::binary */
  125. {
  126. std::ofstream ofs(binary_file, std::ios::out | std::ios::binary);
  127. if (!ofs.is_open()) {
  128. std::cerr << "打开二进制文件写入失败" << std::endl;
  129. return 1;
  130. }
  131. /* 2. write(数据地址(需转成char*), 字节数)
  132. * reinterpret_cast<const char*> 把任意类型指针转换为 char* 字节流,
  133. * 这是C++里进行二进制IO的标准写法。
  134. */
  135. ofs.write(reinterpret_cast<const char*>(students_out.data()),
  136. sizeof(Student) * students_out.size());
  137. std::cout << "写入了 " << students_out.size() << " 条学生记录\n";
  138. }
  139. /* 3. 以二进制读模式打开并读回 */
  140. {
  141. std::ifstream ifs(binary_file, std::ios::in | std::ios::binary);
  142. if (!ifs.is_open()) {
  143. std::cerr << "打开二进制文件读取失败" << std::endl;
  144. return 1;
  145. }
  146. std::vector<Student> students_in(2);
  147. ifs.read(reinterpret_cast<char*>(students_in.data()),
  148. sizeof(Student) * students_in.size());
  149. // gcount() 返回上一次read实际读取到的字节数,可用于校验是否读满
  150. std::streamsize actually_read = ifs.gcount();
  151. size_t record_count = actually_read / sizeof(Student);
  152. std::cout << "读取了 " << record_count << " 条学生记录:\n";
  153. for (size_t i = 0; i < record_count; i++) {
  154. std::cout << " id=" << students_in[i].id
  155. << ", name=" << students_in[i].name
  156. << ", score=" << students_in[i].score << std::endl;
  157. }
  158. }
  159. /* ---------------------------------------------------------
  160. * 第三部分:追加写入演示 (std::ios::app)
  161. * --------------------------------------------------------- */
  162. std::cout << "\n===== [C++] 追加写入演示 =====\n";
  163. {
  164. std::ofstream ofs(text_file, std::ios::app); // 追加模式,不清空原内容
  165. if (ofs.is_open()) {
  166. ofs << 3 << "," << "Charlie" << "," << 77.0 << "\n";
  167. std::cout << "已追加一行到 " << text_file << std::endl;
  168. }
  169. }
  170. /* ---------------------------------------------------------
  171. * 第四部分:使用fstream同时读写同一个文件(C++特有的便利类)
  172. * --------------------------------------------------------- */
  173. std::cout << "\n===== [C++] fstream 读写同一文件演示 =====\n";
  174. {
  175. // in | out 表示既能读也能写;文件必须已存在(不加trunc就不会清空)
  176. std::fstream fs(text_file, std::ios::in | std::ios::out);
  177. if (fs.is_open()) {
  178. std::string first;
  179. std::getline(fs, first);
  180. std::cout << "fstream读到第一行: " << first << std::endl;
  181. // 还可以继续用 fs << ... 写入,实现同一个流对象读写混合操作
  182. }
  183. }
  184. std::cout << "\nC++语言文件读写演示结束。\n";
  185. return 0;
  186. }