9
文件
2
文件系统
缓冲型文件系统,
系统自动在内存中为每个文件开辟一个缓冲区,
作为程序和磁盘文件数据交流的中间媒介,
3、关闭文件
(写入磁盘 )
变量
(内存 )
2、
读写文件
(磁盘 )1、打开文件(写入缓冲区 )
文件缓冲区
(内存 )
三步中的每一步都是通过 C语言的库函数实现
3
与文件输入输出相关的库函数
#include <stdio.h>
打开,fopen();
读/写:
fgetc(); fputc();
fgets(); fputs();
fread(); fwrite();
fscanf(); fprintf();
文件定位指针
rewind(); fseek(); ftell();feof();
关闭,fclose();
法宝,每个库函数在调用时可以查询。
TC,CTRL+F1
VC 输入函数名即可看到函数形参。
4
要解决的问题 1:
将学生信息存入文件,再从文件调入数组
#include<stdio.h>
#define N 30
struct stu
{char name[10];
int num;
int age;
char addr[15];
};
5
1、输入学生信息存入数组
void main()
{struct stu boya[N],boyb[N],*pp,*qq;
FILE *fp; /*定义一个用于指向 FILE类型的指针 fp*/
int i;
printf("\ninput data\n");
for(i=0,pp=boya;i<N;i++,pp++)
scanf("%s%d%d%s",pp->name,&pp->num,&pp-
>age,pp->addr);
FILE类型是在 stdio.h文件中定义的。
typedef struct{
int level; /*缓冲区‘满’或‘空’的程度 */
unsigned flags; /*文件状态标志 */
char fd; /*文件描述符 */
unsig ed char hold; /*如无缓冲区不读字符 */
short bsize; /*缓冲区的大小 */
unsigned char *buffer;/*数据缓冲区的位置 */
unsigned char *curp; /*文件定位指针 */
unsigned istemp; /*临时文件指示器 */
short token; /*用于有效性检查 */
} FILE;
6
2、存入文件 (打开文件 ->存储 ->关闭文件 )
/*先要打开文件 */
if((fp=fopen("stu_list.dat","wb+"))==NULL)
{ printf("Cannot open file strike any key exit!");
exit(1);
}
FILE *fopen(char *filename,char * type);
–例,FILE *fp = fopen("C:\\CONFIG.SYS","rw");
–filename是文件名
包含路径。如果不含路径,表示打开当前目录下的文件
–type是打开方式
常用为 "r","w","rw"和 "a",分别表示只读、
只写、读写和添加
,b”表示二进制文件,不写,b”表示文本文件
–返回值为指向此文件的指针,留待以后使用
–如果打开失败,返回值为 NULLint a=30000;
1,ASCII码文件中存储格式,‘ 3’,‘0’,‘0’,‘0’,‘0’,(5个字节 )
2,二进制文件中存储格式,30000的补码 (2个字节 ),即
11101010 01100000
二者各有特点,
ASCII文件浪费空间和时间,直观二进制文件节省空间和时间,不直观
7
2、存入文件 (打开文件 ->存储 ->关闭文件 )
/*存入文件 (输出到文件 )*/
for(i=0,pp=boya;i<N;i++,pp++)
fprintf(fp,"%s %d %d %s\n",pp->name,pp->num,pp-
>age,pp->addr);
如果存储的全部是字符类型,也可以用
fwrite( pp,sizeof(struct stu),1,fp);
int fprintf(FILE *fp,char *format,arg1,…,
argn)
函数功能,按照 format给出的控制符格式,将变元
arg1,…,argn的值写入到 fp所指向的文件中去 。
unsigned fwrite(void *ptr,unsigned size,unsigned
numb,FILE *fp);
函数功能:把从 ptr开始的 numb个 size大小的数据块写入 fp
指向的文件,函数调用成功返回 count的值,否则返回 -1。
当写一个字符或一个字符串时,可用 fputc()和 fputs().
int fputc(int c,FILE *fp);
–功能:向 fp输出字符 c
–若写入错误,则返回 EOF,否则返回 c
–例,fputc(?a?,fp); /*将字符 a写到 fp指向的文件 */
int fputs(char *s,FILE *fp);
功能:将字符串写到 fp指向的文件中去
成功时返回 0,出错时返回 EOF
例,fputs(“abcde”,fp); /*将字符串写到 fp指向的文件 */
8
2、存入文件 (打开文件 ->存储 ->关闭文件 )
/*最后关闭文件 */
fclose(fp);
int fclose(FILE *fp);
函数功能:关闭文件,此时,fp不再指向文件在内存的缓冲区。
返回值:关闭成功时返回值为 0。否则 (如磁盘空间不足、写保护或关闭已经关闭的文件 )返回 EOF,
即 -1。
9
3、从文件读入到数组
(打开文件 ->读入到数组 ->关闭文件 )
if((fp=fopen("stu_list.dat","rb"))==NULL)
{ printf("Cannot open file strike any key exit!");
exit(2);
}
for(i=0;i<2;i++,qq++)
fscanf(fp,"%s %d %d %s\n",qq->name,&qq-
>num,&qq->age,qq->addr);
printf("\n\nname\tnumber age addr\n");
qq=boyb;
for(i=0;i<2;i++,qq++)
fprintf(stdout,"%s\t%5d %7d %s\n",qq->name,qq-
>num,qq->age,qq->addr);
fclose(fp);
}
输出到 stdout文件,即输出到屏幕。
其实,从键盘输入、输出到屏幕与报错都是以文件的形式来存储信息,
这三个 标准设备文件 分别是
stdin,stdout,stderr
从用户角度对文件分类,可分为两类:标准设备文件和普通磁盘文件
10
要解决的问题 2:复制文件
输入两个文件名
打开这两个文件
将一个文件的内容复制到另外一个文件中
关闭这两个文件
11
#include<stdio.h>
#include<stdlib.h>
void main()
{
FILE *fp1,*fp2;
char ch,file1[30],file2[30];
printf("Input source file,");
scanf("%s",file1); /*输入源文件名 */
printf("Input object file,");
scanf("%s",file2); /*输入目的文件名 */
if((fp1=fopen(file1,"r"))==NULL)
{ printf("Cannot open %s\n",file1);
exit(1);
} /*打开源文件 */
if((fp2=fopen(file2,"w"))==NULL)
fp2=stdout; /*打开目的文件,找不到的话输出到屏幕 */
/*从源文件中读一个字符,并写入目的文件中 */
while((ch=fgetc(fp1))!=EOF)
fputc(ch,fp2);
fclose(fp1); /*关闭两个文件 */
fclose(fp2);
}
12
/*copy.c*/
#include<stdio.h>
#include<stdlib.h>
void main( int argc,char *argv[] )
{
FILE *fp1,*fp2;
char ch;
if(argc!=3)
{puts("error in parameters!");
exit(0);
}
if((fp1=fopen( argv[1],"r"))==NULL)
{ printf("Cannot open %s\n",argv[1]);
exit(1);
} /*打开源文件 */
if((fp2=fopen( argv[2],"w"))==NULL)
fp2=stdout; /*打开目的文件,找不到的话输出到屏幕 */
/*从源文件中读一个字符,并写入目的文件中 */
while((ch=fgetc(fp1))!=EOF)
fputc(ch,fp2);
fclose(fp1); /*关闭两个文件 */
fclose(fp2);
}
/*该程序编译后,要在 dos命令行下输入 3个参数方能运行,
第一个是该程序的名字 copy,
第二个是源文件名,第三个是目的文件名。整个程序的功能是实现文件复制 */
13
如何随机读写文件的某一部分?
前边对文件的读写都是从头开始,按顺序读
(写 )。如何只读写文件的某一部分呢?
除有 FILE *类型的指针 fp指向文件的开始外,
还有一个 char *类型的文件定位指针 curp,
指向文件内部下一个要读 (写 )的字符。
我们可以通过改变 curp的位置实现随机读写。
……………………
……………………
……………………
……………………
……………………
…………………,..
fp 文件定位指针 curp
14
几个相关函数
void rewind(FILE *fp);
功能:让 fp中的文件定位 指针 指向文件开始位置
int fseek(FILE *fp,long offset,int fromwhere);
功能:把 fp中的文件定位 指针移动到相应位置
fromwhere:
SEEK_SET或 0-----文件开始
SEEK_CUR或 1-----当前位置
SEEK_END或 2-----文件末尾
long ftell(FILE *fp);
功能:返回 fp中文件定位指针所在的位置
int feof(FILE *fp);
功能:当文件位置指针指向 fp末尾时,返回非 0值,否则返回 0
例,while(feof(fp)==0)
{c=fgetc(fp);}
15
#include<stdio.h>
struct stu
{ char name[10];
int num;
int age;
char addr[15];
}boy,*qq=&boy;
void main()
{ FILE *fp;
if((fp=fopen("stu.txt","rt"))==NULL)
{ printf("Cannot open file strike any key exit!");
exit(1);
}
rewind(fp); /*将文件定位指针移至文件开始位置 */
fseek(fp,18,1); /*如果每个学生在文件中占 18个字节,”略”过 1个学生所占的 18个字节 */
fscanf(fp,"%s%d%d%s",qq->name,&qq->num,&qq->age,qq->addr);
/*读第 2个学生信息至 qq*/
printf(“\n\nname\tnumber age addr\n”); /*输出第 2个学生信息 */
printf("%s\t%5d %7d %s\n",qq->name,qq->num,qq->age,qq->addr);
fclose(fp);
}
例 3
16
例 4:程序结构,
float Fun1(float x)/*函数 1定义 */
{…}
float Fun2(float x) /*函数 2定义 */
{…}
float Integral(float (*f)(float),float a,float b)
{…} /* 求积分函数定义 */
void main()
{…
y1=Integral(Fun1,a,b); /*对函数 1求积分 */
y2=Integral(Fun2,a,b); /*对函数 2求积分 */
…
}
实参是函数名,形参是指向函数的指针其实,函数名也就是函数在内存中的首地址,
指向函数的指针定义为:
int (*p)();/*定义一个变量 p,
是用来指向返回值为 int的函数的 */
指针的初始化为:
p=max;/*f指向 fun1*/
函数调用时,可采用如下方式:
–max(a,b);
–P(a,b);
–(*p)(a,b);
–!!! (*max)(a,b)与*
p(a,b)不行
17
函数指针变量作函数参数
/*函数功能:求函数 f在 [a,b]的积分 */
float Integral(float (*f)(),float a,float b)
{ float s,h,y; int n,i;
s = ((*f)(a)+(*f)(b))/2.0;
n = 100;
h = (b-a)/n;
for (i=0;i<n;i++)
{ y = a+i*h;
s += (*f)(y);
}
return s*h;
}
18
小结
文件的相关概念及相关库函数的调用
带参数的 main()
指向函数的指针
19
重点
循环,圣经,,
只要重复做一件事,就要用循环语句,此时考虑循环从哪儿开始,满足什么条件继续循环,每次重复的是什么?
函数,圣经,,
函数调用,其实就是任务交接,此时,应指定任务交接给谁
(函数名 ),要告知他哪些信息 (实参 )才能完成任务?而在调用之前,你必须有一个函数能够完成你所移交的任务,即要先有函数定义,定义时想象自己是完成任务的那个人,而完成这个任务需要知道什么信息 (形参 ),完成以后是否有结果 (返回值 )。
数据:循环处理多个数据
指针,圣经,,定义指针的根本目的就是根据指针找到数据。
指针 p指向哪儿?间接引用的数据 (*p)是多少?
是指针指向发生了变化 (p=?),还是间接引用的数据发生了变化 (*p)=?。
20
结束语
课程已全部结束,剩下的时间请大家认真复习,
准备考试。具体考试时间,18周星期一六 (6月 23
日 )16:10-18:10
考试内容:大纲中的内容,抓住重点
答疑方式:
邮件答疑
问题较多请至旧行政楼 206(数理学院二楼 )
有重要通知我会及时在网上公布,请随时关注我的个人主页 http://cs.cqupt.edu.cn/xiejb
谢谢大家一个学期的配合。
希望大家能够 活学活用 C语言 。
文件
2
文件系统
缓冲型文件系统,
系统自动在内存中为每个文件开辟一个缓冲区,
作为程序和磁盘文件数据交流的中间媒介,
3、关闭文件
(写入磁盘 )
变量
(内存 )
2、
读写文件
(磁盘 )1、打开文件(写入缓冲区 )
文件缓冲区
(内存 )
三步中的每一步都是通过 C语言的库函数实现
3
与文件输入输出相关的库函数
#include <stdio.h>
打开,fopen();
读/写:
fgetc(); fputc();
fgets(); fputs();
fread(); fwrite();
fscanf(); fprintf();
文件定位指针
rewind(); fseek(); ftell();feof();
关闭,fclose();
法宝,每个库函数在调用时可以查询。
TC,CTRL+F1
VC 输入函数名即可看到函数形参。
4
要解决的问题 1:
将学生信息存入文件,再从文件调入数组
#include<stdio.h>
#define N 30
struct stu
{char name[10];
int num;
int age;
char addr[15];
};
5
1、输入学生信息存入数组
void main()
{struct stu boya[N],boyb[N],*pp,*qq;
FILE *fp; /*定义一个用于指向 FILE类型的指针 fp*/
int i;
printf("\ninput data\n");
for(i=0,pp=boya;i<N;i++,pp++)
scanf("%s%d%d%s",pp->name,&pp->num,&pp-
>age,pp->addr);
FILE类型是在 stdio.h文件中定义的。
typedef struct{
int level; /*缓冲区‘满’或‘空’的程度 */
unsigned flags; /*文件状态标志 */
char fd; /*文件描述符 */
unsig ed char hold; /*如无缓冲区不读字符 */
short bsize; /*缓冲区的大小 */
unsigned char *buffer;/*数据缓冲区的位置 */
unsigned char *curp; /*文件定位指针 */
unsigned istemp; /*临时文件指示器 */
short token; /*用于有效性检查 */
} FILE;
6
2、存入文件 (打开文件 ->存储 ->关闭文件 )
/*先要打开文件 */
if((fp=fopen("stu_list.dat","wb+"))==NULL)
{ printf("Cannot open file strike any key exit!");
exit(1);
}
FILE *fopen(char *filename,char * type);
–例,FILE *fp = fopen("C:\\CONFIG.SYS","rw");
–filename是文件名
包含路径。如果不含路径,表示打开当前目录下的文件
–type是打开方式
常用为 "r","w","rw"和 "a",分别表示只读、
只写、读写和添加
,b”表示二进制文件,不写,b”表示文本文件
–返回值为指向此文件的指针,留待以后使用
–如果打开失败,返回值为 NULLint a=30000;
1,ASCII码文件中存储格式,‘ 3’,‘0’,‘0’,‘0’,‘0’,(5个字节 )
2,二进制文件中存储格式,30000的补码 (2个字节 ),即
11101010 01100000
二者各有特点,
ASCII文件浪费空间和时间,直观二进制文件节省空间和时间,不直观
7
2、存入文件 (打开文件 ->存储 ->关闭文件 )
/*存入文件 (输出到文件 )*/
for(i=0,pp=boya;i<N;i++,pp++)
fprintf(fp,"%s %d %d %s\n",pp->name,pp->num,pp-
>age,pp->addr);
如果存储的全部是字符类型,也可以用
fwrite( pp,sizeof(struct stu),1,fp);
int fprintf(FILE *fp,char *format,arg1,…,
argn)
函数功能,按照 format给出的控制符格式,将变元
arg1,…,argn的值写入到 fp所指向的文件中去 。
unsigned fwrite(void *ptr,unsigned size,unsigned
numb,FILE *fp);
函数功能:把从 ptr开始的 numb个 size大小的数据块写入 fp
指向的文件,函数调用成功返回 count的值,否则返回 -1。
当写一个字符或一个字符串时,可用 fputc()和 fputs().
int fputc(int c,FILE *fp);
–功能:向 fp输出字符 c
–若写入错误,则返回 EOF,否则返回 c
–例,fputc(?a?,fp); /*将字符 a写到 fp指向的文件 */
int fputs(char *s,FILE *fp);
功能:将字符串写到 fp指向的文件中去
成功时返回 0,出错时返回 EOF
例,fputs(“abcde”,fp); /*将字符串写到 fp指向的文件 */
8
2、存入文件 (打开文件 ->存储 ->关闭文件 )
/*最后关闭文件 */
fclose(fp);
int fclose(FILE *fp);
函数功能:关闭文件,此时,fp不再指向文件在内存的缓冲区。
返回值:关闭成功时返回值为 0。否则 (如磁盘空间不足、写保护或关闭已经关闭的文件 )返回 EOF,
即 -1。
9
3、从文件读入到数组
(打开文件 ->读入到数组 ->关闭文件 )
if((fp=fopen("stu_list.dat","rb"))==NULL)
{ printf("Cannot open file strike any key exit!");
exit(2);
}
for(i=0;i<2;i++,qq++)
fscanf(fp,"%s %d %d %s\n",qq->name,&qq-
>num,&qq->age,qq->addr);
printf("\n\nname\tnumber age addr\n");
qq=boyb;
for(i=0;i<2;i++,qq++)
fprintf(stdout,"%s\t%5d %7d %s\n",qq->name,qq-
>num,qq->age,qq->addr);
fclose(fp);
}
输出到 stdout文件,即输出到屏幕。
其实,从键盘输入、输出到屏幕与报错都是以文件的形式来存储信息,
这三个 标准设备文件 分别是
stdin,stdout,stderr
从用户角度对文件分类,可分为两类:标准设备文件和普通磁盘文件
10
要解决的问题 2:复制文件
输入两个文件名
打开这两个文件
将一个文件的内容复制到另外一个文件中
关闭这两个文件
11
#include<stdio.h>
#include<stdlib.h>
void main()
{
FILE *fp1,*fp2;
char ch,file1[30],file2[30];
printf("Input source file,");
scanf("%s",file1); /*输入源文件名 */
printf("Input object file,");
scanf("%s",file2); /*输入目的文件名 */
if((fp1=fopen(file1,"r"))==NULL)
{ printf("Cannot open %s\n",file1);
exit(1);
} /*打开源文件 */
if((fp2=fopen(file2,"w"))==NULL)
fp2=stdout; /*打开目的文件,找不到的话输出到屏幕 */
/*从源文件中读一个字符,并写入目的文件中 */
while((ch=fgetc(fp1))!=EOF)
fputc(ch,fp2);
fclose(fp1); /*关闭两个文件 */
fclose(fp2);
}
12
/*copy.c*/
#include<stdio.h>
#include<stdlib.h>
void main( int argc,char *argv[] )
{
FILE *fp1,*fp2;
char ch;
if(argc!=3)
{puts("error in parameters!");
exit(0);
}
if((fp1=fopen( argv[1],"r"))==NULL)
{ printf("Cannot open %s\n",argv[1]);
exit(1);
} /*打开源文件 */
if((fp2=fopen( argv[2],"w"))==NULL)
fp2=stdout; /*打开目的文件,找不到的话输出到屏幕 */
/*从源文件中读一个字符,并写入目的文件中 */
while((ch=fgetc(fp1))!=EOF)
fputc(ch,fp2);
fclose(fp1); /*关闭两个文件 */
fclose(fp2);
}
/*该程序编译后,要在 dos命令行下输入 3个参数方能运行,
第一个是该程序的名字 copy,
第二个是源文件名,第三个是目的文件名。整个程序的功能是实现文件复制 */
13
如何随机读写文件的某一部分?
前边对文件的读写都是从头开始,按顺序读
(写 )。如何只读写文件的某一部分呢?
除有 FILE *类型的指针 fp指向文件的开始外,
还有一个 char *类型的文件定位指针 curp,
指向文件内部下一个要读 (写 )的字符。
我们可以通过改变 curp的位置实现随机读写。
……………………
……………………
……………………
……………………
……………………
…………………,..
fp 文件定位指针 curp
14
几个相关函数
void rewind(FILE *fp);
功能:让 fp中的文件定位 指针 指向文件开始位置
int fseek(FILE *fp,long offset,int fromwhere);
功能:把 fp中的文件定位 指针移动到相应位置
fromwhere:
SEEK_SET或 0-----文件开始
SEEK_CUR或 1-----当前位置
SEEK_END或 2-----文件末尾
long ftell(FILE *fp);
功能:返回 fp中文件定位指针所在的位置
int feof(FILE *fp);
功能:当文件位置指针指向 fp末尾时,返回非 0值,否则返回 0
例,while(feof(fp)==0)
{c=fgetc(fp);}
15
#include<stdio.h>
struct stu
{ char name[10];
int num;
int age;
char addr[15];
}boy,*qq=&boy;
void main()
{ FILE *fp;
if((fp=fopen("stu.txt","rt"))==NULL)
{ printf("Cannot open file strike any key exit!");
exit(1);
}
rewind(fp); /*将文件定位指针移至文件开始位置 */
fseek(fp,18,1); /*如果每个学生在文件中占 18个字节,”略”过 1个学生所占的 18个字节 */
fscanf(fp,"%s%d%d%s",qq->name,&qq->num,&qq->age,qq->addr);
/*读第 2个学生信息至 qq*/
printf(“\n\nname\tnumber age addr\n”); /*输出第 2个学生信息 */
printf("%s\t%5d %7d %s\n",qq->name,qq->num,qq->age,qq->addr);
fclose(fp);
}
例 3
16
例 4:程序结构,
float Fun1(float x)/*函数 1定义 */
{…}
float Fun2(float x) /*函数 2定义 */
{…}
float Integral(float (*f)(float),float a,float b)
{…} /* 求积分函数定义 */
void main()
{…
y1=Integral(Fun1,a,b); /*对函数 1求积分 */
y2=Integral(Fun2,a,b); /*对函数 2求积分 */
…
}
实参是函数名,形参是指向函数的指针其实,函数名也就是函数在内存中的首地址,
指向函数的指针定义为:
int (*p)();/*定义一个变量 p,
是用来指向返回值为 int的函数的 */
指针的初始化为:
p=max;/*f指向 fun1*/
函数调用时,可采用如下方式:
–max(a,b);
–P(a,b);
–(*p)(a,b);
–!!! (*max)(a,b)与*
p(a,b)不行
17
函数指针变量作函数参数
/*函数功能:求函数 f在 [a,b]的积分 */
float Integral(float (*f)(),float a,float b)
{ float s,h,y; int n,i;
s = ((*f)(a)+(*f)(b))/2.0;
n = 100;
h = (b-a)/n;
for (i=0;i<n;i++)
{ y = a+i*h;
s += (*f)(y);
}
return s*h;
}
18
小结
文件的相关概念及相关库函数的调用
带参数的 main()
指向函数的指针
19
重点
循环,圣经,,
只要重复做一件事,就要用循环语句,此时考虑循环从哪儿开始,满足什么条件继续循环,每次重复的是什么?
函数,圣经,,
函数调用,其实就是任务交接,此时,应指定任务交接给谁
(函数名 ),要告知他哪些信息 (实参 )才能完成任务?而在调用之前,你必须有一个函数能够完成你所移交的任务,即要先有函数定义,定义时想象自己是完成任务的那个人,而完成这个任务需要知道什么信息 (形参 ),完成以后是否有结果 (返回值 )。
数据:循环处理多个数据
指针,圣经,,定义指针的根本目的就是根据指针找到数据。
指针 p指向哪儿?间接引用的数据 (*p)是多少?
是指针指向发生了变化 (p=?),还是间接引用的数据发生了变化 (*p)=?。
20
结束语
课程已全部结束,剩下的时间请大家认真复习,
准备考试。具体考试时间,18周星期一六 (6月 23
日 )16:10-18:10
考试内容:大纲中的内容,抓住重点
答疑方式:
邮件答疑
问题较多请至旧行政楼 206(数理学院二楼 )
有重要通知我会及时在网上公布,请随时关注我的个人主页 http://cs.cqupt.edu.cn/xiejb
谢谢大家一个学期的配合。
希望大家能够 活学活用 C语言 。