| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- /*
- * ============================================================
- * C语言文件读写示例 (c_file_io.c)
- * ============================================================
- *
- * C语言使用标准库 <stdio.h> 中提供的一组函数来操作文件,
- * 核心是 FILE* 这个"文件指针"(其实是一个不透明的结构体指针,
- * 内部保存了文件描述符、缓冲区、读写位置等信息)。
- *
- * 常用函数:
- * FILE* fopen(const char *path, const char *mode); // 打开文件
- * int fclose(FILE *fp); // 关闭文件
- * int fprintf(FILE *fp, const char *fmt, ...); // 格式化写入(文本)
- * int fscanf(FILE *fp, const char *fmt, ...); // 格式化读取(文本)
- * char* fgets(char *buf, int n, FILE *fp); // 按行读取文本
- * size_t fwrite(const void *ptr, size_t size, size_t n, FILE *fp); // 二进制写
- * size_t fread(void *ptr, size_t size, size_t n, FILE *fp); // 二进制读
- * int feof(FILE *fp); // 是否到达文件末尾
- * int ferror(FILE *fp); // 是否发生错误
- *
- * 打开模式 mode 常见取值:
- * "r" 只读,文件必须存在
- * "w" 只写,文件不存在则创建,存在则清空
- * "a" 追加写,文件不存在则创建
- * "r+" 读写,文件必须存在
- * "w+" 读写,文件不存在则创建,存在则清空
- * "a+" 读写追加
- * 在 mode 后加 "b" 表示以二进制模式打开,如 "rb"、"wb"
- * (在 Windows 上文本模式会自动转换 \n <-> \r\n,二进制模式不转换)
- *
- * 特点总结:
- * 1. 面向过程,需要手动检查返回值判断是否成功(没有异常机制)。
- * 2. 必须显式调用 fclose 关闭文件,否则可能造成资源泄漏或数据未刷新到磁盘。
- * 3. 类型不安全:fprintf/fscanf 依赖格式化字符串 %d/%s 等,容易出错。
- * 4. 性能高、历史悠久,几乎所有C库、嵌入式系统都在用。
- * ============================================================
- */
- #include <stdio.h> // 标准输入输出:fopen/fclose/fprintf/fscanf/fread/fwrite等
- #include <stdlib.h> // exit, EXIT_FAILURE
- #include <string.h> // strlen
- /* 定义一个简单的结构体,用于演示二进制读写 */
- typedef struct {
- int id;
- char name[32];
- double score;
- } Student;
- int main(void)
- {
- const char *text_file = "c_demo.txt";
- const char *binary_file = "c_demo.bin";
- /* ---------------------------------------------------------
- * 第一部分:文本文件的写入与读取
- * --------------------------------------------------------- */
- printf("===== [C语言] 文本文件读写演示 =====\n");
- /* 1. 打开文件用于写入("w" 模式:不存在则创建,存在则清空) */
- FILE *fp = fopen(text_file, "w");
- if (fp == NULL) {
- /* fopen 失败时返回 NULL,必须手动判断 */
- perror("fopen 写入失败");
- return EXIT_FAILURE;
- }
- /* 2. 使用 fprintf 按格式化文本写入,用法类似 printf,只是多了一个 FILE* 参数 */
- fprintf(fp, "Hello from C!\n");
- fprintf(fp, "%d,%s,%.2f\n", 1, "Alice", 95.5);
- fprintf(fp, "%d,%s,%.2f\n", 2, "Bob", 88.0);
- /* 3. 用完必须关闭,fclose 会把缓冲区数据刷新(flush)到磁盘,并释放FILE*资源 */
- fclose(fp);
- printf("已写入文件: %s\n", text_file);
- /* 4. 重新打开文件用于读取 */
- fp = fopen(text_file, "r");
- if (fp == NULL) {
- perror("fopen 读取失败");
- return EXIT_FAILURE;
- }
- /* 5. 使用 fgets 按行读取文本,最多读取 sizeof(line)-1 个字符,会保留末尾的'\n' */
- char line[128];
- printf("--- 按行读取内容 ---\n");
- while (fgets(line, sizeof(line), fp) != NULL) {
- printf("读到一行: %s", line); // line里已经带了换行符
- }
- /* 判断循环结束的原因:是正常到达文件末尾,还是发生了读取错误 */
- if (ferror(fp)) {
- perror("读取过程中发生错误");
- }
- fclose(fp);
- /* 6. 也可以用 fscanf 按格式解析文本(适合读取结构化数据,例如 "id,name,score") */
- fp = fopen(text_file, "r");
- if (fp != NULL) {
- char first_line[64];
- fgets(first_line, sizeof(first_line), fp); // 跳过第一行 "Hello from C!"
- int id; char name[32]; double score;
- printf("--- 使用fscanf解析结构化数据 ---\n");
- while (fscanf(fp, "%d,%31[^,],%lf\n", &id, name, &score) == 3) {
- printf("解析结果: id=%d, name=%s, score=%.2f\n", id, name, score);
- }
- fclose(fp);
- }
- /* ---------------------------------------------------------
- * 第二部分:二进制文件的写入与读取(更高效,不做文本转换/格式化)
- * --------------------------------------------------------- */
- printf("\n===== [C语言] 二进制文件读写演示 =====\n");
- Student students_out[2] = {
- {1, "Alice", 95.5},
- {2, "Bob", 88.0}
- };
- /* 1. 以二进制写模式打开 "wb" */
- fp = fopen(binary_file, "wb");
- if (fp == NULL) {
- perror("fopen 二进制写入失败");
- return EXIT_FAILURE;
- }
- /* 2. fwrite(数据指针, 每个元素大小, 元素个数, 文件指针)
- * 直接把内存中的字节按原样写入文件,速度快,但不同平台字节序/结构体对齐可能不同,
- * 不适合跨平台/跨编译器长期保存数据。
- */
- size_t written = fwrite(students_out, sizeof(Student), 2, fp);
- printf("写入了 %zu 条学生记录\n", written);
- fclose(fp);
- /* 3. 以二进制读模式打开 "rb" 并读回 */
- fp = fopen(binary_file, "rb");
- if (fp == NULL) {
- perror("fopen 二进制读取失败");
- return EXIT_FAILURE;
- }
- Student students_in[2];
- size_t read_count = fread(students_in, sizeof(Student), 2, fp);
- printf("读取了 %zu 条学生记录:\n", read_count);
- for (size_t i = 0; i < read_count; i++) {
- printf(" id=%d, name=%s, score=%.2f\n",
- students_in[i].id, students_in[i].name, students_in[i].score);
- }
- fclose(fp);
- /* ---------------------------------------------------------
- * 第三部分:追加写入演示 ("a" 模式)
- * --------------------------------------------------------- */
- printf("\n===== [C语言] 追加写入演示 =====\n");
- fp = fopen(text_file, "a"); // 追加模式,写入内容会加到文件末尾,不会清空原内容
- if (fp != NULL) {
- fprintf(fp, "%d,%s,%.2f\n", 3, "Charlie", 77.0);
- fclose(fp);
- printf("已追加一行到 %s\n", text_file);
- }
- printf("\nC语言文件读写演示结束。\n");
- return 0;
- }
|