因为是以函数的形式完成整个知识点的梳理,可以直接看程序源码进行直接学习哦!!!
欢迎大家参与讨论、纠错~
一、文件的随机读写
(一)知识点引入
前面介绍的对文件的读写方式都是顺序读写,即读写文件只能从头开始,顺序读写各个数据
在实际问题中:要求只读写文件中某一指定的部分,例如:读取文件第200字节处的30个字节
解决方法:可以移动文件内部的位置指针到需要读写的位置再进行读写(随机读写)
实现随机读写的关键:按要求移动位置指针(文件的定位)
完成文件定位的函数有:rewind、ftell、fseek函数
void test16()
{
char buf[128] = "";
FILE* fp = NULL;
fp = fopen("test16.txt", "w+");
if (fp == NULL)
{
perror("fopen");
return;
}
// 先往文件中写入一个字符串"hello file"
fputs("hello file", fp);
fclose(fp);
// 打开一个文件进行操作后需要关闭再重新打开文件让文件的流指针回到文件首部
fp = fopen("test16.txt","r");
// 在从文件找那个读取该字符串
fgets(buf, sizeof(buf), fp);
printf("buf = %s\n", buf);
fclose(fp);
}
不能刚写入就读出,因为这时候系统还不知道你到底要写入多少字节的内容,所以系统会自己预留出一部分的空间,这部分的空间里存储的内容未知(乱码)。在这个时候进行的读操作其实是从文件写入结束的位置开始读取,也就是对那部分未知空间进行读取,得到的内容并不是自己想要的(这里很重要哦!!!)
-
解决上述文件问题:文件写完后,需要关闭文件然后再重新打开文件,让文件流指针指向文件开始位置,然后再开始下次的文件读操作
-
使用rewind和fseek函数改变文件指针指向文件中的位置
(二)rewind:复位文件流指针
-
格式:rewind(文件指针);
-
说明:把内部的位置指针移到文件首,不用再关闭打开了
void test17()
{
char buf[128] = "";
FILE* fp = NULL;
fp = fopen("test17.txt", "w+");
if (fp == NULL)
{
perror("fopen");
return;
}
fputs("hello file", fp);
rewind(fp); // 复位文件流指针(位置指针)
fgets(buf, sizeof(buf), fp);
printf("buf=%s\n", buf);
fclose(fp);
}
(三)ftell:获得文件流指针距离文件首部的字节数
-
格式:ftell(文件指针);
-
说明
获取文件流目前的读写位置
返回当前位置(距离文件起始位置的字节数),出错时返回-1
函数返回值是long型,需要定义一个变量去接收
void test18()
{
char buf[128] = "";
long file_len = 0;
FILE* fp = NULL;
fp = fopen("a.txt", "w+");
if (fp == NULL)
{
perror("fopen");
return;
}
fputs("hello file", fp);
file_len = ftell(fp); // 获取文件流指针距离文件首部的字节数
printf("file_len = %ld\n", file_len); // 10
fclose(fp);
}
(四)fseek:定位文件的流指针(一般用于二进制文件)
-
格式:fseek(文件指针, 位移量, 起始点);
-
说明
用来移动文件流的读写位置
函数返回值是int型
起始点
文件开头 SEEK_SET 0 文件当前位置 SEEK_CUR 1 文件末尾 SEEK_END 2
位移量:以起始点为基点,向前、后移动的字节数(向右+、向左-)
例如
fseek(fp,100,SEEK_SET); // 将位置指针从文件头向前移100个字节处 fseek(fp,-50,SEEK_CUR); // 将位置指针从当前位置向回移动50个字节处 fseek(fp,-50,SEEK_END); // 将位置指针从文件尾 退回50个字节处.
1、练习:将一个未知大小的文件(文本文件)全部读入内存,并显示在屏幕上
-
思路:将文件指针移动到文件末尾,计算整个文件的长度,然后根据获得的文件长度创建空间存储数据
void test19()
{
char* file_data = NULL;
long file_len = 0;
FILE* fp = NULL;
fp = fopen("a.txt", "r");
if (fp == NULL)
{
perror("fopen");
return;
}
// 1、得到文件的总大小
// a、使用fseek将文件指针定位到文件尾部
fseek(fp, 0, 2);
// b、使用ftell计算文件的偏移量 == 文件的总大小
file_len = ftell(fp);
// c、使用rewind复位文件流指针
rewind(fp);
//2、根据文件的总大小合理申请内存空间
file_data = (char*)calloc(1, file_len + 1); // +1的目的内存末尾存放'\0'
if (file_data == NULL)
{
fclose(fp); // 申请失败则退出文件
return;
}
// 3、一次性将文件数据读入到内存空间
fread(file_data, file_len, 1, fp);
// 4、遍历读取到的文件内容
printf("file_len = %ld\n", file_len);
printf("%s\n", file_data);
// 5、释放堆区空间
if (file_data != NULL)
{
free(file_data);
file_data = NULL;
}
fclose(fp);
}
-
与错误提示的综合使用
void test19()
{
FILE *fp = NULL;
fp = fopen("a.txt", "r");
if(ferror(fp))
{
printf(“文件处理出错!”);
}
while (!feof(fp)) // 使用feof函数检测文件指针是否指向了文件末尾
{ // 循环读取到文件末尾后停止
putchar(fgetc(fp));
}
fclose(fp); // 关闭文件指针fp所指向的文件
}
2、练习:往文件中写入两个结构体,读取第二个结构体
struct stu
{
char name[10];
int num;
int age;
}boya[2],boyb;
void test20()
{
FILE* fp = NULL;
fp = fopen("test20.txt", "wb+");
if (fp == NULL)
{
perror("fopen");
return;
}
printf("请输入数据:\n");
for (int i = 0; i < 2; i++)
{
scanf("%s %d %d", boya[i].name, &boya[i].num, &boya[i].age);
}
fwrite(boya, sizeof(boyb), 2, fp);
fseek(fp, sizeof(boyb), SEEK_SET); // 移动到第一行的尾部
fread(&boyb, sizeof(boyb), 1, fp);
printf("%s %d %d", boyb.name, boyb.num, boyb.age);
fclose(fp);
}
二、文件的出差错检测
(一)feof():判断文件是否到达文件末尾
-
格式:feof(文件指针);
-
说明
进行文件错误检测,检测是否读到了文件末尾,文件未结束返回0,文件已结束返回非0
常配合fgetc、fgets、fread等读函数判断是否到文件结束
EOF宏只能用于文本文件
feof函数可以用于文本文件、二进制文件
void test21()
{
FILE* fp = NULL;
fp = fopen("a.txt", "r");
if (fp == NULL)
{
perror("fopen");
return;
}
while (!feof(fp))
{
char ch = fgetc(fp);
printf("%c", ch);
}
fclose(fp);
}
(二)ferror:用于检测文件读写出错
-
格式:ferror(文件指针);
-
说明
检查文件在用各种输入输出函数进行读写时是否出错
比如:以只读方式打开一个文件,调用写函数就会发生错误
只要出现错误标志,就一直保留,直到对同一文件调用clearerr函数或rewind函数,或任何其他一个输入输出函数
返回值:0表示未出错,否则表示有错
void test22()
{
FILE* fp = NULL;
char ch;
fp = fopen("DUMMY.FIL", "w");
ch = getc(fp);
if (ferror(fp)) // 有错则进行错误提示输出
{
printf("Error reading from DUMMY.FIL\n");
clearerr(fp); // 清除错误标志
}
fclose(fp);
}
(三)clearerr:将文件出错标志和文件结束标志置0
-
格式:clearerr(文件指针);
-
说明:用于清除出错标志和文件结束标志,使它们为0值