/* * ============================================================ * C语言文件读写示例 (c_file_io.c) * ============================================================ * * C语言使用标准库 中提供的一组函数来操作文件, * 核心是 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 // 标准输入输出:fopen/fclose/fprintf/fscanf/fread/fwrite等 #include // exit, EXIT_FAILURE #include // 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; }