文件
程序文件
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。
数据文件
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件, 或者输出内容的文件。
文件类型
数据文件称为文本文件或者二进制文件
数据在内存中以二进制形式存储,不转换的输出到外存,就是二进制文件
如果以ASCII码的形式输出到外存中,以ASCII字符形式存储的文件是文本文件
字符用ASCII形式存储,数值型数据可以用ASCII形式存储,也可以用二进制形式存储
文件缓冲区
从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。缓冲区的大小根据C编译系统决定的。

文件的打开关闭
文件指针
FILE
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE。

文件操作的一些函数
fputs(在文件中写入一个字符)
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf=fopen("test.txt","w");
if(pf==NULL)
{
printf("%s\n",strerror(errno));
}
fputc('n',pf);
fputc('i',pf);
fputc('h',pf);
fputc('a',pf);
fputc('o',pf);
fputc('n',pf);
fputc('i',pf);
fclose(pf);
pf=NULL;
return 0;
}
在文件 test.txt 上显示 nihao
fgets(在文件中读出一个字符)
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf=fopen("test.txt","r");
if(pf==NULL)
{
printf("%s\n",strerror(errno));
}
printf("%c",fgetc(pf));
printf("%c",fgetc(pf));
printf("%c",fgetc(pf));
printf("%c",fgetc(pf));
printf("%c",fgetc(pf));
fclose(pf);
pf=NULL;
return 0;
}
编译结果:nihao
标准输入输出流
#include<stdio.h>
int main()
{
int ch=fgetc(stdin);
fputc( ch,stdout);
return 0;
}
输入什么字符就显示什么字符
例如输入 n
编译结果:n
fputs(在文件中写入一行字符串)
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("text.txt","w");
if(pf==NULL)
{
printf("%s\n",strerror(errno));
}
fputs("nihaoa\n",pf);
fputs("are you ok?\n",pf);
fclose(pf);
pf=NULL;
return 0;
}
在text,txt文件中显示:
nihaoa
are you ok?
fgets(从文件中读取一行字符串)?
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
char arr[1024]={0};
FILE* pf = fopen("text.txt","r");
if(pf==NULL)
{
printf("%s\n",strerror(errno));
}
fgets(arr,1024,pf);
printf("%s",arr);
fclose(pf);
pf=NULL;
return 0;
}
提前在 text.txt 文件中写入 Hello!
编译结果:Hello!
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
char arr[1024]={0};
FILE* pf = fopen("text.txt","r");
if(pf==NULL)
{
printf("%s\n",strerror(errno));
}
fgets(arr,1024,pf);
printf("%s",arr);
fgets(arr,1024,pf);
printf("%s",arr);
fclose(pf);
pf=NULL;
return 0;
}
提前在 text.txt 文件中写入
Hello!
World!
编译结果:
Hello!
World!
解释:因为用了两行fgets函数,每用一次,读取一行的字符串。
标准输入输出写法?
#include<stdio.h>
int main()
{
char arr[1024]={0};
fgets(arr,1024,stdin);
fputs(arr,stdout);
return 0;
}
输入:Hello World!
输出:Hello World!
fprintf函数 (将格式化的数据写入文件中)
#include<stdio.h>
#include<string.h>
#include<errno.h>
struct stu
{
int n;
char name[20];
float socre;
};
int main()
{
struct stu s={20,"zhangsan",90.5};
FILE* pf=fopen("text.txt","w");
if(NULL==pf)
{
printf("%s\n",strerror(errno));
}
fprintf(pf,"%d %s %lf",s.n,s.name,s.socre);
return 0;
fclose(pf);
pf=NULL;
}
text.txt 文件中显示:20 ?zhangsan ?90.500000
fscnaf函数(将文件中的数据写入的格式化中)
#include<stdio.h>
#include<string.h>
#include<errno.h>
struct stu
{
int n;
char name[20];
float socre;
};
int main()
{
struct stu s={0};
FILE* pf=fopen("text.txt","r");
if(NULL==pf)
{
printf("%s\n",strerror(errno));
}
fscanf(pf,"%d %s %f",&(s.n),s.name,&(s.socre));
printf("%d %s %f\n",s.n,s.name,s.socre);
fclose(pf);
pf=NULL;
return 0;
}
编译结果:20 ?zhangsan ?90.500000
标准化的输入和输出
#include<stdio.h>
#include<string.h>
#include<errno.h>
struct stu
{
int n;
char name[20];
float socre;
};
int main()
{
struct stu s={0};
fscanf(stdin,"%d %s %f",&(s.n),s.name,&(s.socre));//输入数据写入到结构体中
fprintf(stdout,"%d %s %f",s.n,s.name,s.socre);//将格式化的数据输出出来
return 0;
}
输入:21 ?lisi? 89.5
输出:21 ?lisi ?89.500000
sprintf和sscnaf(将格式化数据转成字符串形式(sprintf)或者字符串数据转成格式化(sscanf))
#include<stdio.h>
struct stu
{
int n;
float age;
char name[20];
};
int main()
{
struct stu s={20,91.5,"xiebiesan"};
struct stu temp={0};
char arr[1024]={0};
sprintf(arr,"%d %f %s",s.n,s.age,s.name);//将格式化的数据(结构体)转换成字符串的数据,存储在arr中。
printf("%s\n",arr);
sscanf(arr,"%d %f %s",&(temp.n),&(temp.age),temp.name);//从arr中读取格式化的数据,存储在结构体temp中。
printf("%d %f %s",temp.n,temp.age,temp.name);
}
编译结果:
20 91.500000 xiaobiesan 20 91.500000 xiaobiesan
一些函数的对比
scanf/printf
针对标准输入流/输出流的格式化输入输出语句
fscanf/fprintf
针对所有输入流/输出流的格式化输入输出语句
sscanf/sprintf
?sscanf:是从字符串中读取格式化的数据
sprintf:是把格式化数据输出成(存储到)字符串
fseek函数(根据文件指针的位置和偏移量来定位文件指针。)
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf=fopen("text.txt","r");
int ch;
if(pf==NULL)
{
printf("%s\n",strerror(errno));
}
fseek(pf,2,SEEK_CUR);
ch=fgetc(pf);
printf("%c\n",ch);
fclose(pf);
pf=NULL;
return 0;
}
提前在 text.txt 文件中写入123456
编译结果:3
ftell函数 (返回文件指针相对于起始位置的偏移量)
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf=fopen("text.txt","r");
int pos;
int ch;
if(pf==NULL)
{
printf("%s\n",strerror(errno));
}
ch=fgetc(pf);
printf("%c\n",ch);
pos=ftell(pf);
printf("%d\n",pos);
fclose(pf);
pf=NULL;
return 0;
}
提前在text.txt 文件中写入987654321
ch=fgetc(pf);
printf("%c\n",ch);
在没有注释掉上面这两段代码前,编译结果为:9 1
注释掉上面的两段代码后,编译结果为:0
fgetc(pf)读取一次后,指针pf向后偏移一次。
rewind函数 (让文件指针的位置回到文件起始的起始位置)
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf=fopen("text.txt","r");
int ch;
if(pf==NULL)
{
printf("%s\n",strerror(errno));
}
fseek(pf,-2,SEEK_END);
ch=fgetc(pf);
printf("%c\n",ch);
rewind(pf);
ch=fgetc(pf);
printf("%c\n",ch);
fclose(pf);
pf=NULL;
return 0;
}
提前在text.txt 文件中写入987654321
编译结果:
2
9
?
文件读取结束的判定
feof函数
牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。
1. 文本文件读取是否结束,判断返回值是否为EOF ( fgetc ),或者NULL ( fgets )
例如:
fgetc 判断是否为EOF 。
fgets 判断返回值是否为NULL 。 ?
2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数。
include<stdio.h>
int main()
{
int ch=0;
FILE* pf=fopen("text.txt","r");
if(pf==NULL)
{
perror("open file text.txt");//perror自带冒号
return 0;
}
while((ch=fgetc(pf))!=EOF)
{
putchar(ch);
}
putchar('\n');
if(ferror(pf))
{
printf("error\n");
}
else if(feof(pf))
{
printf("end of file\n");
}
fclose(pf);
pf=NULL;
}
提前在text.txt 文件中写入123456789
编译结果:
123456789 end of file
|