C语言文件操作详解:顺序读写、随机访问与结束判定

C语言文件操作详解

1. 文件与流

文件使程序数据能够持久保存。C标准库用 FILE * 表示流,并预定义 stdin、stdout、stderr 三个标准流。

2. 打开与关闭

1
2
3
4
5
6
7
8
9
10
FILE *fp = fopen("data.txt", "r");
if (fp == NULL)
{
perror("fopen");
return 1;
}

/* 使用文件 */
fclose(fp);
fp = NULL;

常用模式:

模式 含义
r 只读,文件必须存在
w 只写,清空或创建
a 追加写,创建或在末尾写
r+ 读写,文件必须存在
w+ 读写,清空或创建
a+ 读与追加写
b 二进制模式,如 rb、wb

3. 文本顺序读写

1
fprintf(fp, "%s %d\n", "Lic", 20);
1
2
3
4
char name[32];
int age;
if (fscanf(fp, "%31s%d", name, &age) == 2)
printf("%s %d\n", name, age);

逐字符与逐行接口包括 fgetc/fputc、fgets/fputs。fgets 能限制最大读取长度,通常比无边界输入更安全。

4. 二进制读写

1
2
size_t written = fwrite(arr, sizeof(arr[0]), count, fp);
size_t read_count = fread(arr, sizeof(arr[0]), count, fp);

返回值是成功处理的元素个数,不是字节数。直接写结构体可能受字节序、填充、类型宽度和版本变化影响,不适合作为可移植文件格式。

5. 随机访问

1
2
3
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
rewind(fp);

fseek 可以相对文件开头、当前位置或末尾移动。大型文件和不同平台可能需要更宽的定位接口。

6. 正确判断读取结束

不要使用经典错误:

1
while (!feof(fp)) { /* 读取 */ }

feof 只有在一次读取尝试失败后才会置位。正确做法是以读取函数返回值控制循环:

1
2
3
4
5
6
char line[256];
while (fgets(line, sizeof(line), fp) != NULL)
fputs(line, stdout);

if (ferror(fp))
perror("read");

feof 用于区分“因文件结束失败”还是其他读取错误。

7. 缓冲区

标准I/O通常带缓冲。fflush 可刷新输出流,不要把 fflush(stdin) 当作可移植的输入清理方法。正常 fclose 会刷新输出并释放相关资源。

8. 总结

文件操作要检查每次打开、读取、写入和关闭结果。循环条件应由实际I/O函数返回值决定,同时明确文本格式、二进制格式及跨平台兼容性。