一、引言
文件操作是C语言学习中最实用、也最容易出错的环节之一。无论是处理文本数据、保存程序结果,还是读写配置文件,几乎都离不开对文件的读写控制。很多初学者在学到这里时,常常分不清各种打开模式的区别,也搞不懂二进制读写与文本读写的差异。
本文通过一个完整、可运行的C语言示例程序,系统地讲解文件的写入、追加、逐行读取、二进制读写以及文件定位五类操作,并对每段代码做逐行解析。读完本文,你将能够独立使用 fopen、fclose、fprintf、fputs、fgets、fwrite、fread、fseek 等常用函数完成日常的文件处理任务。
二、环境准备
本文示例基于标准C语言编写,使用任意主流的C语言编译器均可运行,推荐使用 Dev-C++、Visual Studio 或 CodeBlocks。程序运行时,会在当前工作目录下自动生成 test.txt(文本文件)与 binary.bin(二进制文件)。
示例中用到的头文件及作用如下:

三、文件操作核心概念
3.1 FILE 指针
在C语言中,所有的文件操作都通过一个名为 FILE 的结构体指针完成。当我们调用 fopen 打开一个文件时,系统会返回一个指向该文件信息的 FILE 指针,后续的读写函数都依赖这个指针定位到目标文件。若打开失败,fopen 会返回 NULL,因此在每次打开文件后都必须判断返回值。
3.2 fopen 的打开模式
fopen 函数的原型为 FILE *fopen(const char *filename, const char *mode),其中第二个参数 mode 决定了文件的打开方式。常见的模式如下:

3.3 关闭文件
文件使用完毕后,必须调用 fclose(FILE *fp) 关闭文件。及时关闭文件可以释放系统资源,并确保缓冲区中的内容真正写入磁盘,避免数据丢失。
四、完整示例代码
下面给出本文的完整示例程序,代码分为写入、追加、读取、二进制读写、文件定位五个部分:
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LENGTH 100
int main() {
FILE *fp;
char filename[] = "test.txt";
char buffer[MAX_LENGTH];
// 1. 写入文件
fp = fopen(filename, "w"); // 只写,覆盖模式
if (fp == NULL) { perror("无法打开文件"); return 1; }
fprintf(fp, "Hello, World!\n"); // 格式化写入
fputs("This is a test file.\n", fp); // 写入字符串
fclose(fp);
// 2. 追加内容
fp = fopen(filename, "a"); // 追加模式
if (fp == NULL) { perror("无法打开文件"); return 1; }
fputs("Appended line.\n", fp);
fclose(fp);
// 3. 逐行读取
fp = fopen(filename, "r");
if (fp == NULL) { perror("无法打开文件"); return 1; }
printf("文件内容:\n");
while (fgets(buffer, MAX_LENGTH, fp) != NULL) {
printf("%s", buffer); // fgets 包含换行符
}
fclose(fp);
// 4. 二进制文件读写
int numbers[] = {1, 2, 3, 4, 5};
int read_numbers[5];
fp = fopen("binary.bin", "wb"); // 二进制写入
if (fp == NULL) { perror("无法打开二进制文件"); return 1; }
fwrite(numbers, sizeof(int), 5, fp); // 写入5个int
fclose(fp);
fp = fopen("binary.bin", "rb"); // 二进制读取
if (fp == NULL) { perror("无法打开二进制文件"); return 1; }
fread(read_numbers, sizeof(int), 5, fp); // 读取5个int
fclose(fp);
printf("\n二进制文件内容:\n");
for (int i = 0; i < 5; i++) {
printf("numbers[%d] = %d\n", i, read_numbers[i]);
}
// 5. 文件定位:读取文件末尾前10个字节
fp = fopen(filename, "r");
if (fp == NULL) { perror("无法打开文件"); return 1; }
fseek(fp, -10, SEEK_END); // 移动到末尾前10字节
char last_chars[11] = {0};
fread(last_chars, 1, 10, fp);
printf("\n文件最后10个字符: %s\n", last_chars);
fclose(fp);
return 0;
}
五、代码逐模块解析
5.1 文本文件写入("w" 模式)
第一段代码以 "w" 模式打开 test.txt,使用 fprintf 进行格式化写入,再使用 fputs 写入一个字符串。要点如下:
cpp
fp = fopen(filename, "w"); if (fp == NULL) { perror("无法打开文件"); return 1; } fprintf(fp, "Hello, World!\n"); fputs("This is a test file.\n", fp); fclose(fp);
"w" 模式会清空文件原有内容再从头写入,若文件不存在则自动创建。fprintf 与 printf 用法几乎一致,只是多了一个 FILE 指针作为第一个参数;fputs 则用于向文件写入一个字符串(不自动追加换行符,因此示例中手动加上 \n)。
5.2 追加内容("a" 模式)
第二段代码以 "a" 模式重新打开同一个文件并追加一行内容。与 "w" 不同,"a" 模式不会覆盖原有内容,而是将新内容追加到文件末尾:
cpp
fp = fopen(filename, "a"); if (fp == NULL) { perror("无法打开文件"); return 1; } fputs("Appended line.\n", fp); fclose(fp);
5.3 逐行读取文件("r" 模式)
第三段代码以 "r" 模式打开文件,使用 fgets 循环逐行读取。fgets 每次最多读取 MAX_LENGTH-1 个字符,直到遇到换行符或文件末尾,读取的内容(包含换行符)存放在 buffer 中:
cpp
fp = fopen(filename, "r"); if (fp == NULL) { perror("无法打开文件"); return 1; } printf("文件内容:\n"); while (fgets(buffer, MAX_LENGTH, fp) != NULL) { printf("%s", buffer); } fclose(fp);
这里 while 循环的判断条件是 fgets 的返回值是否为 NULL:读到文件末尾时 fgets 会返回 NULL,循环随之结束,从而实现了"逐行读取直到读完"的效果。
5.4 二进制文件读写("wb"/"rb" 模式)
第四段代码演示二进制文件的读写。fwrite 将内存中的 5 个 int 直接以二进制形式写入 binary.bin,fread 再从文件中读回这 5 个整数:
cpp
fwrite(numbers, sizeof(int), 5, fp); fread(read_numbers, sizeof(int), 5, fp);
fwrite 与 fread 的函数原型为 size_t fwrite(const void *ptr, size_t size, size_t count, FILE *fp),三个核心参数分别表示:数据起始地址、单个元素的大小(字节数)、元素个数。二进制方式保存的数据与内存中的表示一致,读写效率高,但不适合直接以文本方式查看。
5.5 文件定位(fseek)
最后一段代码使用 fseek 将文件位置指针定位到"文件末尾前 10 个字节",再用 fread 读取最后 10 个字符:
cpp
fseek(fp, -10, SEEK_END); fread(last_chars, 1, 10, fp);
fseek 的原型为 int fseek(FILE *fp, long offset, int origin),offset 为相对偏移量(负数表示向前),origin 可取 SEEK_SET(文件开头)、SEEK_CUR(当前位置)、SEEK_END(文件末尾)。由于 last_chars 已初始化为 0,最后打印时能正常以字符串形式输出末尾内容。
六、运行结果
程序运行后,控制台将依次输出读取到的文件内容、二进制读回的整数序列,以及文件末尾的 10 个字符,效果大致如下:
cpp
文件内容:
Hello, World!
This is a test file.
Appended line.
二进制文件内容:
numbers[0] = 1
numbers[1] = 2
numbers[2] = 3
numbers[3] = 4
umbers[4] = 5
文件最后10个字符: e. Appended
可以看到,test.txt 中同时包含第一次写入的两行与追加的一行;binary.bin 中读回的 5 个整数与写入时完全一致;文件定位成功读取到末尾的 10 个字符。
七、易错点与注意事项

八、总结
本文通过一个完整的示例程序,系统讲解了C语言文件的五大操作:使用 "w" 模式写入、用 "a" 模式追加、以 "r" 模式逐行读取、通过 fwrite/fread 进行二进制读写,以及借助 fseek 实现文件定位。掌握这些操作后,你就可以灵活地处理各类文本与二进制文件。
建议读者动手将示例代码编译运行一遍,并尝试修改文件路径、改变 fseek 偏移量、读取更大范围的数据,加深对不同模式与函数的理解。遇到报错时,优先检查文件是否成功打开、路径是否正确,以及模式是否与操作匹配。