文件指针
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息,而这些信息保存在一个结构体变量中。该结构体类型是由系统声明的,取名为FILE.
FILE* p;//文件指针
文件的打开和关闭
(1)fopen 用来打开文件,fclose用来关闭文件
//打开文件
FILE* pf = fopen(const char* filename,const char*mode);//如果返回打开失败的话会返回空指针
if(pf==NULL)//这里保证pf打开失败后操作停止
{
perror("fopen")//这是分析打开失败的原因
return 1;//停止操作
}
//关闭文件
int fclose(FILE*stream);
pf=NULL;
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b80535983d884f6d82872a61df7f68b4.png
(2)文件打开方式
“r”只读 如果没有相对应的文件那么就会出错
“w”只写如果没有相对应的文件那么就会创立一个新的文件,如果那个文件存在那么就会使存在的那个文件的内容全部删除,从头开始
“r”(只读)操作文件(没有先对应的文件会报错)
FILE* pf = fopen("test.txt", "r");//如果返回打开失败的话会返回空指针
if (pf == NULL)//这里保证pf打开失败后操作停止
{
perror("fopen");//这是分析打开失败的原因
return 1;//停止操作
}
//关闭文件
int fclose(FILE * stream);
pf = NULL;
return 0;
如果有文件
操作成功
理解 只读和只写
从<文件>里面拿数据到<程序> 这个过程叫读操作
从<程序>里面写数据到<文件>这个过程叫写操作
图片理解
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/f9e20dd0f25543deab858ed8e4b6bbee.p
文件顺序读写
(1)顺序读写函数介绍
文件流,标准输入\出流 (输出)-stdout (输入)-stdin
#include<stdio.h>
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s1 = { "李四",18,80.3 };
FILE* pf = fopen("twt.txt", "w");//如果返回打开失败的话会返回空指针
if (pf == NULL)//这里保证pf打开失败后操作停止
{
perror("fopen");//这是分析打开失败的原因
return 1;//停止操作
}
//写文件-是以文本文件的形式写进去 这样才能看得懂
fprintf(stdout, "%s %d %f", s1.name, s1.age, s1.score);//运用stdout打印在屏幕上
//关闭文件
int fclose(FILE * stream);
pf = NULL;
return 0;
}
(1) 那么我们就可以实现一个<写数据>然后<读数据>的操作
fputc
<写文件>
FILE* pf = fopen("test.txt", "w");//如果返回打开失败的话会返回空指针
if (pf == NULL)//这里保证pf打开失败后操作停止
{
perror("fopen");//这是分析打开失败的原因
return 1;//停止操作
}
//写文件
putc('a',pf);//把一个字符写到指定文件中
//关闭文件
int fclose(FILE * stream);
pf = NULL;
return 0;
<读文件>
在指定文件读,返回int(返回的是字符的ASCLL码值)
**
同理
FILE* pf = fopen("test.txt", "r");//如果返回打开失败的话会返回空指针
if (pf == NULL)//这里保证pf打开失败后操作停止
{
perror("fopen");//这是分析打开失败的原因
return 1;//停止操作
}
//读文件
int a=0;
a = fgetc(pf);//把指定文件中的数据读到程序里
printf("%c",a);
//关闭文件
int fclose(FILE * stream);
pf = NULL;
return 0;
(2) fputs
把一个字符串写到一个文件里
FILE* pf = fopen("tat.txt", "w");//如果返回打开失败的话会返回空指针
if (pf == NULL)//这里保证pf打开失败后操作停止
{
perror("fopen");//这是分析打开失败的原因
return 1;//停止操作
}
//写文件
fputs("abcdefgh",pf);//把abcdefgh这个字符串传到文件里,实际上是把字符串的首地址放到文件里
//关闭文件
int fclose(FILE * stream);
pf = NULL;
return 0;
fgets
从流(文件)里面读数据,读到的字符放在一个数组里,num是读取的个数(其中最后一个是’\0‘)这样我们就只能读(num-1)个字符
FILE* pf = fopen("test.txt", "r");//如果返回打开失败的话会返回空指针
if (pf == NULL)//这里保证pf打开失败后操作停止
{
perror("fopen");//这是分析打开失败的原因
return 1;//停止操作
}
//读文件
char arr[20]={0};
fgets(arr,10,pf);//读10-1个字符 读到arr里面 从pf FILE*指针里面读(流)
//关闭文件
int fclose(FILE * stream);
pf = NULL;
return 0;
fgets读取出错时或者读到文件末尾时会返回NULL(空指针)
如果想要让fgets读取文件的所有元素
FILE* pf = fopen("test.txt", "r");//如果返回打开失败的话会返回空指针
if (pf == NULL)//这里保证pf打开失败后操作停止
{
perror("fopen");//这是分析打开失败的原因
return 1;//停止操作
}
//读文件
char arr[20]={0};
while(fgets(arr,10,pf))//读10-1个字符 读到arr里面 从pf FILE*指针里面读(流)
{
printf("%s",arr);
}
//关闭文件
int fclose(FILE * stream);
pf = NULL;
return 0;
fgets会拆成多次打印直到出错或遇到文件末尾
(3)fprintf(各式化的输出函数)
这与printf的函数就差了个文件指针
struct s s1 = { "李四",18,80.3 };
FILE* pf = fopen("twt.txt", "w");//如果返回打开失败的话会返回空指针
if (pf == NULL)//这里保证pf打开失败后操作停止
{
perror("fopen");//这是分析打开失败的原因
return 1;//停止操作
}
//写文件-是以文本文件的形式写进去 这样才能看得懂
fprintf(pf, "%s %d %f", s1.name, s1.age, s1.score);
//关闭文件
int fclose(FILE * stream);
pf = NULL;
return 0;
fscanf(格式化的输出函数)格式化就可以打印浮点型数字等等
多了个FILE* 文件指针
struct B
{
char name[20];
int gae;
float score;
};
int main()
{
struct B b={0};
//想从文件twt.txt中读取数据放在结构体B中
FILE* f=fopen("twt.txt","r");
if(f==NULL)
{
perror("fopen");
return 1;
}
//读文件
fscanf(f,"%s %d %f",b.name,&(b.age),&(b.score))//这里的name已经是地址了所以不用&
printf("%s %d %f",b.name,b.age,b.score);
//关闭文件
fclose(f);
f=NULL;
(4)函数对比
printf-把数据以格式化的形式打印在标准输出流上
fprintf-把数据以格式化的形式打印在指定的输入流上
sprintf 把格式化的数据打印到字符数组里
对比一下 sprintf的功能是以格式化的数据转换成字符串
printf的功能是把格式化数据打印到标准流里
操作
struct S
{
char name[20];
int age;
float score;
};
int main()
{
char arr[200]={0};
struct S s={"张三",20,65.5};
sprintf(arr,"%s %d %f",s.name,s.age,s.score);//把格式化的数据以字符的方式打印到字符数组里
printf("%s\n",arr);
return 0;
}
scnaf -从标准输入流上读取格式化的数据(标准输入流就是以键盘输入到程序中)
fscanf - 从指定输出入流上读取格式化的数据
sscanf - 在字符串中读取格式化数据
对比scanf与sscanf就是多了一个字符数组
struct S
{
char name[20];
int age;
float score;
};
int main()
{
char arr[200] = { 0 };
struct S s = { "张三",20,65.5 };
sprintf(arr, "%s %d %f", s.name, s.age, s.score);//把格式化的数据以字符的方式打印到字符数组里
struct S s1 = { 0 };
sscanf(arr, "%s %d %f", s1.name, &(s1.age), &(s1.score));//从字符串读取数据
printf("%s %d %f",s1.name,&s1.age&,s1.score);
printf("%s\n", arr);
return 0;
(5)fwrite与fread
ptr是个数组地址,把ptr的数据以二进制形式写到文件中
size是数组的类型
count是指要写几个数据到文件中
FILE*stream是文件地址
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写数据
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
fwrite(arr, sizeof(arr), 5, pf);
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fread
与fwrite对比参数一样
从pf文件中读count个数据打印到数组ptr里
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int arr[10] = { 0 };
//写数据
fread(arr, sizeof(arr), 5, pf);
int i = 0;
for (i = 0;i < 5;i++)
{
printf("%d ", arr[i]);
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fread返回值size_t返回1为真返回0为假
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("taat.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读数据
int arr1[5] = { 0 };
int i = 0;
while (fread(&arr1[i], sizeof(int), 1, pf))
{
printf("%d ", arr1[i]);
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
文件的随机读取
1:fseek
而起始位置有三种选择
(1):SEEK_SET 文件起始位置
(2):SEEK_CUR文件的当前位置
(3):SEEK_END文件末尾
#include<stdio.h>
int main()
{
//打开文件
FILE* p = fopen("tbt.txt", "w");
if (p == NULL)
{
perror("fopen");
return 1;
}
//写文件
fputs("abcdefg",p);
//关闭文件
fclose(p);
p = NULL;
FILE* pf = fopen("tbt.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
int a = fgetc(pf);
printf("%c\n", a);
fseek(pf, 4,SEEK_CUR);//改变光标指向的值
a = fgetc(pf);//在让a等于getc(pf)
printf("%c", a);//以字符类型打印a
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
当第一次以fgetc来取字符是,光标位于第一位
而经过fseek的操控后光标偏移到指定地点
ftell
返回文件指针相对于起始位置的偏移量
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("tgt.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fputs("abcdefgh", pf);
//关闭文件
fclose(pf);
pf = NULL;
//打开文件
FILE* p = fopen("tgt.txt", "r");
if (p == NULL)
{
perror("fopen");
return 1;
}
//读文件
int ch = 0;
ch = fgetc(p);
fseek(p, 0, SEEK_END);
printf("%d", ftell(p));
//关闭文件
fclose(p);
p = NULL;
return 0;
}
rewind
测试一下
#include<stdio.h>
int main()
{
FILE* pf = fopen("tgt.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("abcdefgh", pf);
fclose(pf);
pf = NULL;
FILE* p = fopen("tgt.txt", "r");
if (p == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
ch = fgetc(p);
printf("%c\n", ch);
fseek(p, 0, SEEK_END);
rewind(p);
ch = getc(p);
printf("%c", ch);
fclose(p);
p = NULL;
return 0;
}
文件读取结束的判定
feof
fgetc-如果读取正常返回的是字符的ASCLL码值
-如果读取的过程中遇到文件末尾,或发生错误,就返回EOF
fgets 如果读取正常,返回的是存储读取到的字符串的字符数组的地址
如果读取过程中遇到文件末尾或发生错误,返回NULL
feof 功能 :来检测文件末尾是否被标记,如果被标记了就返回一个大于0的值,没有被设置的话就返回一个0.
ferror
ferror去检测错误标记被设置了,那么就会返回非0值否则就返回0;
#include<stdio.h>
int main()
{
FILE* p = fopen("test.txt", "r");
if (p == NULL)
{
perror("fopen");
return 1;
}
//读文件
int ch = 0;
while ((ch = fgetc(p)) != EOF)//当ch等于EOF时就跳出while
{
printf("%c", ch);
}
//采用feof来判断
if (feof(p))
{
printf("遇到文件末尾,读取正常结束");
}
else if (ferror(p))//
{
perror("fgetc");//打印出错误原因
}
return 0;
}