文件的随机读写:
fseek函数:
前面讲解了顺序读写的相关函数,这里介绍一些可以**"指哪写哪的函数"**
有三个参数:
1、文件的地址
2、相对于第三个参数origin偏移的位置
3、起始位置(有三种)
第一种:SEEK_SET(开头)
第二种:SEEK_CUR(当前位置)
第三种:SEEK_END(结尾)
cpp
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("abcdef", pf);
fclose(pf);
pf = NULL;
return 0;
}
可以通过fseek改变光标位置,而且是覆盖改写:
什么意思呢?
如以下代码:
cpp
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("abcdef", pf);
fseek(pf, 2, SEEK_SET);//从头开始往后两个位置
fputs("aa", pf);
fclose(pf);
pf = NULL;
return 0;
}
还可以这样改:
cpp
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("abcdef", pf);
fseek(pf, 2, SEEK_SET);//从头开始往后两个位置开始
fputs("aa", pf);
fseek(pf, 3, SEEK_CUR);//从当前位置开始
fputs("kikll", pf);
fclose(pf);
pf = NULL;
return 0;
}
ftell函数:
返回文件指针相对于起始位置的偏移量
cpp
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("abcdef", pf);
fseek(pf, 2, SEEK_SET);//从头开始往后两个位置
fputs("aa", pf);
int ret = ftell(pf);
printf("%d\n", ret);
fclose(pf);
pf = NULL;
return 0;
}
rewind函数:
让文件指针的位置回到文件的起始位置
cpp
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "w+");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char arr[27];
char a = 0;
for (a = 'A'; a <= 'z'; a++)
{
fputc(a, pf);
}
rewind(pf);
fread(arr, 1, 26, pf);
fclose(pf);
pf = NULL;
arr[26] = '\0';
printf("%s\n", arr);
return 0;
}
**文件读取结束的判定
到此为止讨论了所有文件的相关函数及操作,但是有一点我们还是有点不清楚,一个函数读取文件什么时候停止呢?停止的标志是什么呢?
那如果读取文件中途读取失败又会怎么样,返回的值类型是什么?
接下来就详细探究探究以上函数什么时候读取结束?
feof函数:
feof函数可以检查并判断文件是否为正常结束。
当读取到文件末尾时结束读取,feof会返回一个非零的值,但是读的时候也会有异常结束的时候 ,这时候返回的值就是0。
用feof判断文件是否结束还是失败是不行的。
所以这里就需要用到每个函数读取是否结束的返回值进行判断!
文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets ) 例如: fgetc 判断是否为 EOF . fgets 判断返回值是否为 NULL .
二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。 例如: fread判断返回值是否小于实际要读的个数。
拷贝一份文件
cpp
int main()
{
FILE* pf = fopen("test.txt", "w+");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int a = 0;
for (a = 'A'; a <= 'Z'; a++)
{
fputc(a, pf);
if (a % 5 == 0)
{
fputc('\n', pf);
}
}
rewind(pf);//找到起始位置
FILE* pf1 = fopen("cool.txt", "w");
if (pf1 == NULL)
{
perror("fopen");
fclose(pf);
pf = NULL;
return 1;
}
int ch = 0;
while ((ch = fgetc(pf)) != EOF)
{
fputc(ch,pf1);
}
fclose(pf1);
pf1 = NULL;
fclose(pf);
pf = NULL;
return 0;
}
改进通讯录(可以保存在文件中)
之前写的通讯录经过多次修改,现在可以动态化存储,单数唯一的缺点是,当运行结束后,所有的信息也会跟着销毁,不会被存储起来,现在有办法将其存储在文件中,为此要用的时候,可以打开,这样存储的信息就不会丢失了。
结束之前将信息存入文件
我们用fwrite写入文件,fread读取文件内容。
cpp
void savecontact(con* pc)
{
FILE* pf = fopen("contact.txt", "wb");//二进制打开文件输出
if (pf == NULL)
{
perror("fopen");
return ;
}
int i = 0;
for (i = 0; i < pc->num; i++)
{
fwrite(pc->contact + i,sizeof(per),1,pf);
}
fclose(pf);
pf = NULL;
}
因为fwrite返回的值为读取的值,一次性读取的值我们可以进行设置
参数num为每次读取的值,当读取的值比设置的小,则返回之际读取的个数。
所以选择用while循环一次一次读取!!
开始时写入文件中保存的内容
cpp
void inputcontact(con* pc)
{
FILE* pf = fopen("contact.txt","rb");
if (pf == NULL)
{
perror("inputcontact");
return;
}
//录入信息
per tmp = { 0 };
while (fread(&tmp, sizeof(per), 1, pf))
{
checkcapacity(pc);
pc->contact[pc->num] = tmp;
pc->num++;
}
//关闭文件
fclose(pf);
pf = NULL;
}