完整教程:C语言文件操作函数解析

前言 文件操作是C语言编程中至关重要的一部分,它连接着程序与外部世界,实现了数据的持久化存储。无论是简单的文本处理,还是复杂的数据管理,都离不开文件操作。本文将通过一系列完整的代码示例,全面解析C语言中各种文件操作函数的使用方法、适用场景以及最佳实践。从基础的字符读写到高级的文件定位,从文本模式到二进制模式,我们将深入探讨每一个细节。

目录

前言

字符级文件操作:fputc与fgetc

数据写入:fputc函数

数据读取:fgetc函数

字符串级文件操作:fputs与fgets

批量写入:fputs函数

批量读取:fgets函数

格式化文件操作:fprintf与fscanf

结构体数据写入

结构体数据读取

内存格式化:sprintf与sscanf

二进制文件操作:fwrite与fread

二进制数据写入

二进制数据读取

文件定位操作

fseek函数:随机访问

ftell函数:获取当前位置

rewind函数:重置文件指针

错误处理机制

文件操作状态检测

综合应用实例

总结

核心技术要点

实际应用建议

学习价值

字符级文件操作:fputc与fgetc数据写入:fputc函数

FILE* pf1 = NULL;

pf1 = fopen("text1.txt", "w");

if (pf1 == NULL)

{

perror("fopen");

return 1;

}

for (char i = 'A'; i <= 'Z'; i++)

{

fputc(i, pf1);

}

fputc('\n', pf1);

for (char i = 'a'; i <= 'z'; i++)

{

fputc(i, pf1);

}

fputc('\n', pf1);

for (char i = '0'; i <= '9'; i++)

{

fputc(i, pf1);

}

fclose(pf1);

pf1 = NULL;

功能分析:

创建并打开文件"text1.txt"用于写入

分三段写入数据:大写字母、小写字母、数字

每段结束后添加换行符

最终生成格式化的文本文件

技术要点:

fputc每次写入一个字符

适合精确控制每个字符的写入

自动处理字符到字节的转换

数据读取:fgetc函数

FILE* pf2 = NULL;

pf2 = fopen("text1.txt", "r");

if (pf2 == NULL)

{

perror("fopen");

return 1;

}

char ch = 0;

while ((ch = fgetc(pf2)) != EOF)

{

putchar(ch);

}

fclose(pf2);

pf2 = NULL;

功能分析:

打开刚才创建的文件进行读取

使用循环逐个字符读取直到文件结束

用putchar将读取的字符输出到屏幕

技术要点:

fgetc返回int类型,用char接收可能有问题

EOF是文件结束标志,值为-1

这种方式可以处理任意大小的文件

字符串级文件操作:fputs与fgets批量写入:fputs函数

char arr1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789";

FILE* pf3 = NULL;

pf3 = fopen("text2.txt", "w");

if (pf3 == NULL)

{

perror("fopen");

return 1;

}

fputs(arr1, pf3);

fclose(pf3);

pf3 = NULL;

功能分析:

使用单个字符串包含所有数据

fputs一次性写入整个字符串

比逐个字符写入更高效

优势:

代码更简洁

执行效率更高

适合已知完整内容的情况

批量读取:fgets函数

FILE* pf4 = NULL;

pf4 = fopen("text2.txt", "r");

if (pf4 == NULL)

{

perror("fopen");

return 1;

}

int n = sizeof(arr1) / sizeof(arr1[0])-1;

printf("n=%d", n);

char* p = (char*)malloc((n+1)*sizeof(char));

if (p == NULL)

{

perror("malloc");

fclose(pf4);

return 1;

}

while (fgets(p, n + 1, pf4) != NULL)

{

printf("%s", p);

}

free(p);

p = NULL;

fclose(pf4);

pf4 = NULL;

技术要点:

fgets会读取直到换行符或指定长度减1

自动在字符串末尾添加空字符

需要合理设置缓冲区大小

返回NULL表示读取结束或出错

格式化文件操作:fprintf与fscanf结构体数据写入

struct S

{

char name[20];

int age;

float score;

char c;

};

struct S s = { "xiaoming",20,98.8f,'X' };

FILE* pf5 = NULL;

pf5 = fopen("text3.txt", "w");

if (pf5 == NULL)

{

perror("fopen");

return 1;

}

fprintf(pf5,"%s %d %f %c",s.name,s.age,s.score,s.c);

fclose(pf5);

pf5 = NULL;

功能分析:

定义结构体存储复合数据

使用fprintf按指定格式写入文件

保持数据字段的可读性

结构体数据读取

FILE* pf6 = NULL;

pf6 = fopen("text3.txt", "r");

if (pf6 == NULL)

{

perror("fopen");

return 1;

}

struct S t = { 0 };

struct S u = { 0 };

fscanf(pf6, "%s %d %f %c", t.name, &(t.age), &(t.score), &(t.c));

fscanf(stdin, "%s %d %f %c", t.name, &(t.age), &(t.score), &(t.c));

printf("%s %d %f %c", t.name, t.age, t.score, t.c);

fprintf(stdout, "\n%s %d %f %c\n", s.name, s.age, s.score, s.c);

fclose(pf6);

pf6 = NULL;

技术要点:

fscanf从文件按格式读取数据

可以重定向到标准输入(stdin)

fprintf可以输出到标准输出(stdout)

需要注意数据类型和指针的使用

内存格式化:sprintf与sscanf

struct M

{

char name[20];

int age;

float score;

char c;

};

struct M m = { "lihao",30,98.8f,'M' };

char o[200] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

sprintf(o,"%s %d %f %c", m.name, m.age, m.score, m.c);

printf("%s\n", o);

struct M n = { 0 };

sscanf(o, "%s %d %f %c", n.name, &(n.age), &(n.score), &(n.c));

printf("%s %d %f %c\n", n.name, n.age, n.score, n.c);

功能分析:

sprintf将格式化的数据写入字符串缓冲区

sscanf从字符串中按格式提取数据

实现内存中的数据格式转换

应用场景:

数据序列化和反序列化

字符串处理和数据解析

协议数据的组装和解析

二进制文件操作:fwrite与fread二进制数据写入

int arr1[] = { 1,2,3,4,5 };

FILE* pf7 = fopen("test4.txt", "wb");

if (pf7 == NULL)

{

perror("fopen");

return 1;

}

int sz = sizeof(arr1) / sizeof(arr1[0]);

fwrite(arr1, sizeof(arr1[0]), sz, pf7);

fclose(pf7);

pf7 = NULL;

技术要点:

"wb"模式以二进制方式写入

fwrite直接写入内存数据,不进行字符转换

保持数据的原始格式,适合数值数组、结构体等

二进制数据读取

int arr2[8] = { 0 };

FILE* pf8 = fopen("test4.txt", "rb");

if (pf8 == NULL)

{

perror("fopen");

return 1;

}

int i = 0;

int n = 0;

while (n = fread(arr2, sizeof(int), 4, pf8))

{

for (int j = 0; j < n; j++)

{

printf("%d ", arr2[j]);

}

printf("\n");

}

for (int k = 0; k < 8; k++)

{

printf("%d ", arr2[k]);

}

fclose(pf8);

pf8 = NULL;

技术要点:

"rb"模式以二进制方式读取

fread返回实际读取的元素个数

可以分块读取大文件

保持数据精度,无字符转换损失

文件定位操作fseek函数:随机访问

FILE* pf = fopen("test5.txt", "r");

if (pf == NULL)

{

perror("fopen");

return 1;

}

int ch = fgetc(pf);

printf("%c\n", ch);

fseek(pf, -4, SEEK_END);

ch = fgetc(pf);

printf("%c\n", ch);

fclose(pf);

pf = NULL;

定位模式:

SEEK_SET:从文件开头定位

SEEK_CUR:从当前位置定位

SEEK_END:从文件末尾定位

应用价值:

实现文件的随机访问

适合数据库、索引文件等场景

提高大文件处理效率

ftell函数:获取当前位置

FILE* pf = fopen("test5.txt", "r");

if (pf == NULL)

{

perror("fopen");

return 1;

}

int ch = fgetc(pf);

printf("%c\n", ch);

fseek(pf, 0, SEEK_END);

printf("%d\n", ftell(pf));

fclose(pf);

pf = NULL;

功能:

返回当前文件位置相对于开头的偏移量

常用于获取文件大小

结合fseek实现复杂定位

rewind函数:重置文件指针

FILE* pf = fopen("test5.txt", "r");

if (pf == NULL)

{

perror("fopen");

return 1;

}

int ch = fgetc(pf);

printf("%c\n", ch);

fseek(pf, -4, SEEK_END);

ch = fgetc(pf);

printf("%c\n", ch);

rewind(pf);

ch = fgetc(pf);

printf("%c\n", ch);

fclose(pf);

pf = NULL;

功能:

将文件位置指针重置到开头

等价于fseek(pf, 0, SEEK_SET)

简化代码,提高可读性

错误处理机制文件操作状态检测

FILE* pf = fopen("test5.txt", "r");

if (pf == NULL)

{

perror("fopen");

return 1;

}

int ch = 0;

while ((ch = fgetc(pf)) != EOF)

{

printf("%c\n", ch);

}

if (feof(pf))

{

printf("遇到文件末尾,读取正常结束\n");

}

else if (ferror(pf))

{

perror("fgetc");

}

fclose(pf);

pf = NULL;

错误检测函数:

feof:检测是否到达文件末尾

ferror:检测文件操作是否出错

perror:输出详细的错误信息

最佳实践:

每次文件操作后检查状态

区分正常结束和异常结束

提供有意义的错误信息

综合应用实例

FILE* pf = fopen("test5.txt", "r");

if (pf == NULL)

{

perror("fopen");

return 1;

}

char ch = 0;

for (ch = 'a'; ch <= 'z'; ch++)

{

fputc(ch, pf);

}

if (feof(pf))

{

printf("遇到文件末尾,读取正常结束\n");

}

else if (ferror(pf))

{

perror("fputc");

}

fclose(pf);

pf = NULL;

代码分析:

以读取模式打开文件却进行写入操作

这会触发错误状态

演示了错误检测机制的实际应用

总结通过本文的全面解析,我们深入掌握了C语言文件操作的各个方面:

核心技术要点操作粒度选择

字符级:fgetc/fputc - 精确控制

字符串级:fgets/fputs - 高效处理

格式化:fscanf/fprintf - 结构化数据

二进制:fread/fwrite - 原始数据

文件打开模式

文本模式:字符转换,适合文本文件

二进制模式:无转换,适合数据文件

文件定位能力

随机访问:fseek + ftell

重置指针:rewind

大大扩展了文件处理能力

健壮性保障

全面的错误检测

资源泄漏预防

异常情况处理

实际应用建议根据需求选择合适函数

配置文件:格式化I/O

日志文件:字符串I/O

数据文件:二进制I/O

大文件:分块读取+定位

重视错误处理

始终检查返回值

区分不同错误类型

保证资源正确释放

性能优化考虑

缓冲区大小设置

减少I/O操作次数

合理使用二进制模式

学习价值掌握这些文件操作技术,不仅能够处理日常的文件任务,更重要的是培养了系统编程的思维方式。理解数据在内存和外部存储之间的流动,对于后续学习数据库、网络编程、操作系统等高级主题都具有重要意义。

文件操作是C语言编程的基石之一,扎实掌握这些知识将为你的编程之路奠定坚实的基础。

Copyright © 2022 九州天命装备站 - 装备获取&角色养成活动 All Rights Reserved.