第九讲 - C程序设计基础

Download Report

Transcript 第九讲 - C程序设计基础

九、文件
9.1
9.2
9.3
9.4
9.5
文件概述
文件打开和关闭
文本文件的输入与输出
二进制文件的输入与输出
其他文件库函数
9.1 文件概述
• 文件是存储在外部介质上的数据的集合,由操作
系统来管理。最常用的是磁盘文件。
• 从文件数据的组织形式可分为文本文件和二进制
文件。
 源程序文件一般是文本文件
 数据文件可是文本文件, 也可是二进制文件
• C语言把文件都看作“字节流”文件,也称“流
式文
件”,对文件的读写是以字节为单位的。
 C语言中的文本文件的每个字节代表一个字符,
存放的是该字符的ASCII码
 C语言中的二进制文件是把数据按其在内存中的
存储形式照原样输出到磁盘上
• C语言中对文件处理的方法可分为两种:
 缓冲文件系统
系统自动为打开的文件开辟其各自的内存缓冲区,
本章介绍的文本文件和二进制文件都属此种
 非缓冲文件系统
系统不自动开辟内存缓冲区,而由用户根据需要
在程序中设定
9.2 文件打开和关闭
1.文件类型(FILE)指针
• FILE 类型
处理一个文件须知它的各种信息,这些信息由
系统将其构成一个结构体类型,取名 FILE,谓
之文件类型,其定义放在stdio.h头文件中。
typedef struct
{ short level;
/* fill/empty level of buffer */
unsigned flags;
/* File status flags */
char fd;
/* File descriptor */
unsigned char hold; /* Ungetc char if no buffer */
short bsize;
/* Buffer size */
unsigned char *buffer; /* Data transfer buffer */
unsigned char *curp;
/* Current active pointer */
unsigned istemp;
/* Temporary file indicator */
short
token;
/* Used for validity checking */
} FILE;
/* This is the FILE object */
• FILE类型指针
包含了stdio.h头文件就可用FILE来定义文件类型
的指针变量。
如:
FILE *fp;
可以使fp指向某一文件的结构体变量,从而可通
过该结构体变量中的各项信息来实现对该文件的
操作。
一个文件指针用来操作一个文件。如有n个文件,
一般应定义 n 个文件类型指针变量来分别指向 n
个文件。
2.文件打开函数 fopen( )
FILE *fopen ( char *filename, char *mode )
其中:
• filename(文件名)为要打开文件的文件名及其
路径(字符串),可写成:
"c:\\tc\\test.dat"
或定义过 char s[ ] = "c:\\tc\\test.dat"; 则写 s;
或定义过 char *p = "c:\\tc\\test.dat"; 则写 p;
或定义过 #define ff "c:\\tc\\test.dat"; 则写 ff 。
• mode 为文件使用方式或称打开方式,可以是:
"r" — 只读,为输入打开一个文本文件;
"w" — 只写,为输出打开一个文本文件;
"a" — 追加,向文本文件尾追加数据;
"rb" — 只读,为输入打开一个二进制文件;
"wb" — 只写,为输出打开一个二进制文件;
"ab" — 追加,向二进制文件尾追加数据;
"r+" — 读写,为读/写打开一个文本文件;
"w+"— 读写,为读/写建立一个新文本文件;
"a+" — 读写,为读/写(追加)打开一个文本文件。
"rb+" — 读写,为读/写打开一个二进制文件;
"wb+"— 读写,为读/写建立一个新二进制文件;
"ab+" — 读写,为读/写(追加)打开一个二进制
文件。
• 打开文件常用如下语句:
if ((fp=fopen("file1.dat", "r"))==NULL)
{ printf ("cannot open this file.\n");
exit ( );
}
如果调用fopen()成功,返回一文件类型指针,否
则返回一空指针。
其中exit( ) 是个进程控制库函数,其作用是关闭
所有文件,终止程序运行。原型为:
void exit( int status )
3. 文件关闭函数 fclose( )
原型: int fclose(FILE *fp)
如果文件关闭成功,返回0,如检测到任何错误,
则返回EOF(即-1,在头文件stdio.h中定义)。
9.3
文本文件的输入与输出
9.3.1 读写一个字符的函数
1. 读一个字符的函数 fgetc()
原型:int fgetc(FILE *fp)
功能:从一打开的文件中读一个字符,返回该字
符。文件中有一个指向当前位置的指针自动后移
一个字符。反复调用可一直读到文件结束。文件
结束或出错时,返回EOF。
C语言提供了一个检测文件结束函数:
int feof(FILE *fp)
如果文件结束, 返回非0值, 否则返回0。
例:设计程序读一个源程序文件,并在屏幕上显
示。源程序文件名为:"c:\tc\hello.c"。
# include "stdio.h"
main( )
{ FILE *fp;
char ch;
if((fp=fopen("c:\\tc\\hello.c","r" ))==NULL)
{ printf("cannot open this file.\n"); exit( ); }
ch=fgetc(fp);
while(feof(fp)==0) { putchar(ch); ch=fgetc(fp); }
fclose(fp);
}
其中:
ch=fgetc(fp);
while(feof(fp)==0) { putchar(ch); ch=fgetc(fp); }
也可写成:
while(!feof(fp)) { ch=fgetc(fp); putchar(ch); }
或:
while((ch=fgetc(fp))!=EOF) putchar(ch);
2. 写一个字符的函数 fputc( )
原型:int fputc(char ch, FILE *fp)
功能:将字符 ch 写到fp指向的文件中去,成功,
则返回该字符,否则返回EOF。
【例9.3】将字符串“Welcome Fleshman!”写入c:\tc
下名为“file1.dat”的磁盘文件中。
#include "stdio.h"
main( )
{ FILE *fp;
char ch;
if((fp=fopen("c:\\tc\\file1.dat","w"))==NULL)
{ printf("cannot open this file.\n"); exit( ); }
while((ch=getchar( ))!='\n')
fputc(ch,fp);
fclose(fp);
}
运行时输入: Welcome Fleshman!
例:复制一个磁盘文件。
#include "stdio.h"
main()
{ FILE *in,*out;
char ch, infile[20], outfile[20];
printf("Enter the infile name:\n";
gets(infile);
printf("Enter the outfile name:\n";
gets(outfile);
if((in=fopen(infile,"r"))==NULL)
{ printf("cannot open infile.\n");
exit( ); }
if((out=fopen(outfile,"r"))==NULL)
{ printf("cannot open outfile.\n");
exit( ); }
while(!feof(in))
fputc(fgetc(in),out);
fclose(in);
fclose(out);
}
9.3.2 字符串读写函数
1. 读字符串函数
原型:char *fgets(char *string, int n, FILE *fp)
功能:从fp指定的文件读取长度为n-1的字符串存
入起始地址为string的内存空间,自动加结束标志
'\0',共占n个字符,返回值为地址string。
若在未读足n-1个字符前遇到换行符'\n'或文件
结束就停止读取。
若读到文件末尾或出错,则返回NULL值。
• 写字符串函数
格式: int fputs(char *string, FILE *fp)
功能:将string指向的字符串写到fp指定的文件。
但不输出字符串结束符。写成功,则返回所写的
最后一个字符,否则返回EOF值。
例(填空):从键盘上输入一个字符串,把其中的
小写字母改成大写,输出到文件test.txt中,然后从
该文件读出此字符串并显示。
#include <stdio.h>
main( )
{ FILE *fp; char str[100]; int i=0;
gets(str);
"w" ))==NULL)
if((fp=fopen("test.txt", _____
{ printf("Can't open this file.\n"); exit(0); }
while(str[i])
{ if(str[i]>='a'&&str[i]<='z') str[i]= str[i]-32
______ ;
fputc(str[i],fp); i++; }
fclose(fp);
"r" );
fp=fopen("test.txt",_____
fgets(str,100, fp); printf("%s\n", str);
fclose(fp); }
【例9.5】 将字符串 "They decided to meet the
following evening. " 加密后写入磁盘文件,该文件名
为"file3.txt"。
加密算法是将信息字符串每个字符和密钥字符串,
唐诗“床前明月光,疑是地上霜,举头望明月……”
的汉语拼音码相加。解密的方法当然是二者相减。
这可从磁盘文件中把密码读到内存后解密验证。
#include <stdio.h>
main()
{ FILE *fp; int len, i;
char s[80]= "They decided to meet the following
evening.",
char r[80]="ChuangqianmingyueguangYishidishang
shuangJjutouwang", a[80];
len=strlen(s);
for (i=0; i<len; i++)
a[i]=s[i]+r[i];
/* 加密运算 */
a[i]='\0';
puts(a);
fp=fopen("file3.txt", "w");
fputs(a, fp);
fclose(fp);
fp=fopen("file3.txt", "r");
fgets(a, len+1, fp);
for (i=0; i<len; i++)
a[i]=a[i]-r[i];
puts(a);
}
/* 显示密码 */
/* 写入文件 */
/* 读文件 */
/* 解密运算 */
/* 显示原信息 */
运行结果:
TC集成环境里会看到加密后的一行乱码,和解密
后的信息:
They decided to meet the following evening.
若用文本编辑器打开文件file3.txt,则只能看到:
椥谮幩痔室彝庅钑姨谡庅廖撐匦这呤芪撏肫苄杠
下次传递信息,你可以更改密钥字符串,当然别忘
了告诉信息接收者
9.3.3 格式化读写函数
• 调用格式:
fscanf ( FILE *fp, 格式说明,输入表列 )
fprintf ( FILE *fp, 格式说明,输出表列 )
• 说明:
 这两个函数与scanf( )和printf( ) 相似,只是读写
对象不同,前者是文件,后者是终端。
 这两个函数读写的是文本文件。
例:有一封英文信,其文件名为:letter.txt。统计
信中大写字母的个数,句子的总数。
#include <stdio.h>
main( )
{ FILE *fp; char c; int k, m;
if((fp=fopen("letter.txt","r"))==NULL)
{ printf("cannot open this file.\n"); exit( ); }
k=m=0;
while(fscanf(fp,"%c", &c)!=EOF)
{ if(c<='Z'&&c>='A') k++;
/* k 统计大写字母 */
if(c=='.') m++;
/* m统计句子 */
printf("%c", c); }
printf("Capital letter numbers:%d\n", k);
printf("Sentence numbers:%d\n",m);
fclose(fp); }
9.4 二进制文件的输入与输出
二进制读写函数:
int fread (void *buf, int size, int n, FILE *fp)
int fwrite(void *buf, int size, int n, FILE *fp)
其中:
void *buf:任何类型指向数据块(首址)的指针,
int size: 要读写的数据块字节数,
int n:
要读写的数据块个数,
FILE *fp: 指向已打开的要读写文件的指针。
读或写成功,返回读或写数据块个数n
功能:从fp指定的文件读取或写入长度为size的n个
数据块,存到或取自buf所指向的内存区。
例:建一函数,把上一章举例的学生数据链表的内
容存入文件。
void save( struct student *head, FILE *fp)
{ struct student *p;
for( p=head; p; p=p->next)
fwrite( p, sizeof(*p), 1, fp);
}
【例9.9】设职工数据为:工号、姓名、性别、年
龄、工资,将6名职工的数据从键盘输入,然后送
入磁盘文件worker1.rec中保存。再读此文件并输出
这些数据,依次打印出来。
#include <stdio.h>
#define SIZE 6
struct worker_type
{ int num, age;
char name[10], sex;
float pay;
} worker[SIZE];
void save( )
{ FILE *fp;
int i;
if((fp=fopen("worker1.rec", "wb"))==NULL)
{ printf("Cannot open file.\n"); exit( ); }
for(i=0, i<SIZE; i++)
{ if(fwrite(&worker[i], sizeof(struct worker_type),
1, fp)!=1)
printf("file write error.\n");
}
fclose(fp);
}
main( )
{ int i; FILE *fp;
for(i=0; i<SIZE; i++)
scanf("%d %s %c %d %f", &worker[i].num,
worker[i].name, &worker[i].sex,
&worker[i].age, &worker[i].pay);
save( );
printf("\n No Name Sex Age Pay\n");
fp=fopen("worker1.rec","rb");
for(i=0; i<SIZE; i++)
{ fread(&worker[i], sizeof(struct worker_type), 1, fp);
printf("%5d %-8s %-5c %-5d %6.2f\n",
worker[i].num, worker[i].name, worker[i].sex,
worker[i].age, worker[i].pay);
}
}
输入和输出结果见教材p272
例(填空):以下程序把从键盘读入的10个整数
以二进制方式写到一个名为bi.dat的新文件中。
#include <stdio.h>
FILE *fp;
main( )
{ int i, j;
if((fp=fopen( "bi.dat"
______, "wb"))==NULL) exit(0);
for(i=0; i<10; i++)
{ scanf("%d",&j);
fp ); }
sizeof(int) 1, __
fwrite(&j, _________,
fclose(fp);
}
9.5 其他文件库函数
9.5.1 文件的定位函数
1. rewind()函数
原型:void rewind( FILE *fp);
功能:将fp指定的文件的当前位置指针重新置于
文件的开头位置。
2. fseek() 函数
原型:int fseek( FILE *fp, long offset, int whence);
功能:将fp指定的文件的当前位置指针移到相对
于由whence指定的位置偏移offset字节的新位置。
若指针移动成功,返回0;若指针移动失败,则
返回非0值。
说明:
whence 为移动位置指针的基准位置,可以是如
下数字或符号常量:
0 或 SEEK_SET 表示文件开始位置
1 或 SEET_CUR 表示文件当前位置
2 或 SEEK_END 表示文件末尾位置
offset 指以whence为基准位置,向前或向后移动
的字节数,值为正时,向文件尾移动,值为负时,
则向文件头移动。
例:( fp是指向文件的指针)
/* 位置指针移到文件开始处 */
fseek(fp, 0L, SEEK_SET);
/* 位置指针移到文件的第20个字节处 */
fseek(fp, 20L, SEEK_SET);
/* 位置指针从当前位置向尾部移动2个字节*/
fseek(fp, 2L, SEEK_CUR);
/* 位置指针移到距文件结尾10个字节处 */
fseek(fp, -10L, SEEK_END);
9.5.2 出错监测函数
1. ftell()函数
原型:long ftell( FILE *fp );
功能:检测fp指定的文件的当前位置,返回相对
于文件开头的位移量(文件第一个字节的位移量
为0)。如出错,则返回-1L。
2. ferror()函数
原型:int ferror( FILE *fp );
功能:检测fp指定的文件是否发生了错误,若没
有错误,返回0;若发生错误,返回非0。
本章结束