Download presentation
Presentation is loading. Please wait.
1
第9章 文件操作 文件 使用文件的目的 操作系统管理数据的基本单位 存储在外存储器上的数据的集合
第9章 文件操作 文件 操作系统管理数据的基本单位 存储在外存储器上的数据的集合 使用文件的目的 程序与数据分离:数据文件的改动不引起程序的改动 数据共享:不同程序可以访问同一数据文件中的数据 能长期保存程序运行的中间数据或结果数据
2
第9章 文件操作 本章要求: 本章重点: 本章难点: 掌握文件的各种操作函数,能对文件进行读写数据操作。
第9章 文件操作 本章要求: 掌握C语言中文件的概念 掌握打开文件的不同模式 掌握使用各种操作函数对文件进行读写的方法 能编写与文件有关的程序 本章重点: 掌握文件的各种操作函数,能对文件进行读写数据操作。 本章难点: 掌握文件的各种操作函数,能对文件进行读写数据操作。
3
9.1.1 文本文件与二进制文件 C语言把文件看作一个字节序列,即由一连串的字节组成,称为“流”,每一个字节都可以单独读取,每一个文件或者以文件结束标志结束,或者在特定的字节号处结束。 按数据的组织形式分类 1、文本文件 又称ASCII文件,每个字节对应一个字符,用于存放该字符的ASCII码,输入输出时对字符逐个处理。 文本文件由文本行组成,每行中可以有0个或多个字符,并以行终止符‘\n’结尾,文件结尾是文件结束标志,该标志后再没有字符出现了。 2、二进制文件 数据按其在内存中的存储形式原样存放
4
【例】整数10000 二进制文件特点: 速度快、便于存放中间结果 文本文件特点: 速度慢、便于对字符操作 内存存储形式 ASCII形式
二进制形式 二进制文件特点: 速度快、便于存放中间结果 文本文件特点: 速度慢、便于对字符操作
5
9.1.2 缓冲文件系统 缓冲文件系统:系统自动地为每一个正在使用的文件在内存中开辟一个缓冲区。
对输入输出进行缓冲,可以大块地转移信息,而不再是一个个字节进行操作。 内存缓冲区的大小,影响着操作外存的次数。内存缓冲区越大,则操作外存的次数就少,执行速度就快、效率高。 文件 程序 数据区 输出文件缓冲区 输入文件缓冲区
6
9.1.3 文件类型指针 FILE *指针变量名; C语言的缓冲文件系统中,用文件类型指针来表示文件。 定义文件类型指针的一般形式:
指针变量用于指向一个文件,实际上是用于存放文件缓冲区的首地址。 FILE结构体是在头文件<stdio.h>中定义的,对文件操作的程序,在最前面都应写上文件包含命令: #include < stdio.h > C语言通过文件指针变量对文件进行打开、读、写及关闭操作。
7
9.1.3 文件类型指针 FILE结构体类型在头文件stdio.h中定义如下:
typedef struct { short level; /*文件缓冲区占用程度*/ unsigned flags; /*文件状态标志*/ char fd; /*文件描述符*/ unsigned char hold; /*若无缓冲区不读取字符*/ short bsize; /*文件缓冲区大小*/ unsigned char *buffer; /*数据缓冲区的位置*/ unsigned char *curp; /*指针当前的位置*/ unsigned istemp; /*临时文件指示器*/ short token; /*用于操作有效性检查*/ } FILE; /*文件类型符*/ 在编程时不必关心FILE结构的具体细节,只需在使用I/O函数时用这个文件指针变量来指定所操作的文件。
8
9.1.3 文件类型指针 在C语言程序中使用文件,需要完成以下工作: 1)声明一个FILE类型的文件指针变量; 2)打开文件:
调用fopen函数将此文件指针变量和某一个实际的磁盘文件相联系。要求指定文件名,并且说明对该文件是输入操作还是输出操作。 3)读写文件: 调用适当的文件操作函数完成必要的I/O操作。 对输入文件来说,函数从文件中将数据读取至程序中; 对输出文件来说,函数将程序中的数据转移到文件中去。 4)关闭文件: 调用fclose函数表明文件操作结束,断开文件指针与实际文件之间的联系。
9
文件指针名=fopen("文件名","文件打开模式")
9.2 文件的打开与关闭 9.2.1 文件的打开 打开文件,实际上是建立文件的各种有关信息,并使文件指针指向该文件; 缓冲文件系统借助文件指针来对文件进行管理和访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。 打开文件使用函数fopen 其调用的一般形式为: 文件指针名=fopen("文件名","文件打开模式") 需要打开的文件的名字 确定文件的 数据操作方式 “文件名”和“文件打开模式”都是字符串常量或字符数组。
10
举 例 作用: 说明: FILE *fp; fp=fopen("source.txt","r");
以读的方式(“r”模式即表示读“read”)打开当前目录下文件名为source.txt的文件。 如果打开文件成功,则返回一个指向source.txt文件信息区的起始地址的指针,并赋值给fp,即fp指向了文件source.txt。其后所有对该文件的操作都必须通过fp指针来实现。 如果文件打开失败,则返回一个空指针NULL,赋值给fp。 说明: 文件名可以包含路径和文件名两部分。 写路径时,因为转义字符以反斜杠开头,所以“\\”才是表示一个反斜杠。 【例】若路径和文件名为:“c:\tc\source.txt”,则应写成“c:\\tc\\source.txt”。
11
9.2.1 文件的打开 文件的打开模式 模式字符串 意 义 "r" 以只读方式打开一个文本文件,只允许读数据 "w"
以只写方式打开或建立一个文本文件,只允许写数据 "a" 以追加方式打开一个文本文件,并在文件末尾写数据 "r+" 以读写方式打开一个文本文件,允许读和写 "w+" 以读写方式打开或建立一个文本文件,允许读写 "a+" 以读写方式打开一个文本文件,允许读,或在文件末追加数 "rb" 以只读方式打开一个二进制文件,只允许读数据 "wb" 以只写方式打开或建立一个二进制文件,只允许写数据 "ab" 以追加方式打开一个二进制文件,并在文件末尾写数据 "rb+" 以读写方式打开一个二进制文件,允许读和写 "wb+" 以读写方式打开或建立一个二进制文件,允许读和写 "ab+" 以读写方式打开一个二进制文件,允许读,或在文件末追加数据
12
9.2.1 文件的打开----模式说明 1)“r”模式: 2)“w”模式: 3)“a”模式:
文件的打开----模式说明 1)“r”模式: 只能用于输入(读操作),且只能打开一个已经存在的文件。 2)“w”模式: 只能用于输出(写操作)。 如果指定的文件不存在,则新建一个文件; 如果文件存在,则把原来的文件删除,再重新建立一个空白的文件。 3)“a”模式: 用于追加操作。 如果指定的文件不存在,则新建该文件; 如果文件存在,保留该文件原有的数据,在原文件的末尾添加新的数据。 4)打开方式带上“b”表示是对二进制文件进行操作。带上“+”表示既可以读,又可以写。而对待文件存在与否的不同处理则按照“r”、“w”、“a”各自的规定。 5)如果在打开文件时发生错误,即打开失败,fopen返回一个空指针NULL。
13
#include <process.h>
文件的打开----模式说明 文件打开可能出现的错误有: 试图以“读”模式(带“r”的方式)打开一个并不存在的文件; 试图以“写”方式(带“w”或“a”的方式、“r+”或“rb+”方式)打开被设置为“只读”属性的文件。 新建一个文件,而磁盘上没有足够的剩余空间或磁盘被写保护。 用不正确的模式打开一个文件可能会破坏文件的内容。 为避免因上述原因的出错,常用以下的方法来打开一个文件: if((fp=fopen("source.txt","r"))==NULL) { printf("This file could not be opened !\n"); exit(0) /*返回操作系统*/ } else { ┇ /*此处编写对文件读/写的代码*/ #include <process.h>
14
9.2 文件的打开与关闭 9.2.2 文件的关闭 fclose(文件指针变量); 【例】fclose(fp)
如果文件成功关闭,fclose函数将返回值0,否则返回EOF。 对文件的操作完成后,应确保关闭程序中打开的文件,以避免文件的数据丢失。 关闭文件指断开指针与文件之间的联系,也就禁止再对该文件进行操作。 磁盘已满、磁盘被移走或者出现I/O错误等都会导致fclose函数执行失败。
15
9.2 文件的打开与关闭 磁盘文件 输出文件缓冲区 输入文件缓冲区 程序数据区 a 缓冲文件系统: fclose 不关闭文件可能会丢失数据
16
9.3 文件的读写 9.3.1 文件读写函数概述 字符读写函数: fgetc()和fputc() 字符串读写函数:fgets()和fputs() 数据块读写函数:freed()和fwrite() 格式化读写函数:fscanf()和fprinf() 文本文件 二进制文件 使用fopen成功打开文件后,都会有属于该文件的一个文件读写位置指针,表示文件内部即将要读写的位置。 文件指针和文件内部的读写位置指针是不同的
17
9.3 文件的读写 文件指针和文件内部的读写位置指针是不同的 文件指针指向整个文件,在程序中定义,只要不重新赋值,文件指针的值不变。
文件内部的读写位置指针用于指示文件内部的当前读写位置,每读写一次,该指针均自动向后移动,指向下一个读写单元。它不需在程序中定义,由系统自动设置。 以“r”或“w”方式打开文件后,该文件读写位置指针初始值指向文件开头; 以“a”方式打开文件后,该文件读写位置指针初始值指向文件末尾。
18
9.3 文件的读写 对文件进行读写操作时,需要判断当前读写位置,如果文件读操作到最后,再进行读写操作就会出错。
为了避免出错,C提供了下面的方式判断文件是否读完 1、对于文本文件,结束标记是EOF(即-1,在stdio.h中定义),可以通过读取的字符是不是结束标记来判断文本文件是否读完; 2、对于二进制文件,没有EOF的结束标志,只能使用系统提供的feof函数来判断; 其中,fp是文件指针变量,如果文件读取结束则返回非0值,没结束返回0值。 3、文本文件可使用feof函数按上面形式来判断是否读取结束。 使用格式是: feof(fp) while( !feof(fp)) { ┇ /*此处写入读操作语句*/ }
19
9.3 文件的读写 9.3.2 字符读写函数 (1)字符读函数fgetc( ) 功能:从指定的文件中读一个字符;
【例】 ch=fgetc(fp1); /*从fp1指向的文件中读取一个字符并送入变量ch中*/ 说明: 在fgetc函数调用中,读取的文件必须是以读或读写方式打开的 读取成功返回文件当前位置的一个字符; 读错误时返回EOF。
20
9.3 文件的读写 9.3.2 字符读写函数 (2)字符写函数fputc( ) 功能:将一个字符写入到指定文件中;
【例】 fputc(ch,fp2); /* 将字符变量ch中的字符写入到fp2所指的文件中 */ 说明: fputc函数也有返回值 若写操作成功,则返回向文件所写的字符; 否则返回EOF,表示写操作失败。
21
9.3 文件的读写 例 9-1 用依次读取字符的方式,将source.txt文件的内容复制到destination.txt文件中。
void main() { FILE *fp1,*fp2; char ch; if((fp1=fopen("C:\\source.txt","r"))==NULL) { printf("File could not be opened!\n"); exit(0); } if((fp2=fopen("C:\\destination.txt","w"))==NULL) exit(0); } while((ch=fgetc(fp1))!=EOF) fputc(ch,fp2); fclose(fp1); fclose(fp2);
22
9.3 文件的读写 9.3.3 字符串读写函数 (1)字符串读函数fgets( ) 功能:从指定的文件中读取一个字符串到程序中的字符数组
字符串读写函数 (1)字符串读函数fgets( ) 功能:从指定的文件中读取一个字符串到程序中的字符数组 函数调用的一般形式: 参数n是一个正整数,表示从文件中读出的字符串不超过n-1个字符。因为要在读入的最后一个字符后加上字符串结束标志'\0'。 说明: fgets函数从文件中读取字符直到遇见回车符或EOF为止,或直到读入了所限定的字符数(至多n-1个字符)为止。 函数读成功返回字符数组首地址;失败返回空指针NULL。 fgets(字符数组名,n ,文件指针);
23
9.3 文件的读写 9.3.2 字符读写函数 (2)字符串写函数fputs( ) 功能:将一个字符串写入到指定文件中 函数调用的一般形式:
字符读写函数 (2)字符串写函数fputs( ) 功能:将一个字符串写入到指定文件中 函数调用的一般形式: 字符串可以是字符串常量,也可以是字符数组名,或字符指针变量。 【例】char *ch="You Are Good!" fputs(ch,fp2); /* 将字符指针ch指向的字符串写入到文件fp2中 */ 说明: 若函数调用fputs返回值为EOF时,表明写操作失败。 fputs(字符串,文件指针)
24
9.3 文件的读写 例9-2 修改例9-1程序,用读取字符串的方式,将source.txt文件的内容复制到destination.txt文件中。 void main() { FILE *fp1,*fp2; char ch[80]; if((fp1=fopen("C:\\source.txt","r"))==NULL) { printf("File could not be opened!\n"); exit(0); } if((fp2=fopen("C:\\destination.txt","w"))==NULL) while(!feof(fp1)) { fgets(ch,81,fp1); fputs(ch,fp2); } fclose(fp1); fclose(fp2); 记得这种把feof当作循环测试条件,造成最后一行打印两次的问题在论坛已经多次出现了。 一句话:忘掉feof,直接用fgets。 当文件刚刚读到文件尾时,feof不会返回true。只有在文件尾部再次进行一次读操作,feof才会返回真。
25
9.3 文件的读写 字符读写函数: fgetc()和fputc() 字符串读写函数:fgets()和fputs() 格式读写函数: fscanf()和fprintf() 数据块读写函数:fread()和fwrite()
26
fscanf(文件指针,"格式字符串",输入表列);
9.3 文件的读写 格式读写函数 (1)格式化读函数fscanf 功能:从指定的文件中按照一定的格式读取数据到程序中 fscanf与scanf功能相似,区别在于fscanf的读取对象是磁盘文件,scanf的读取对象是键盘。 函数调用的一般形式: 其中,格式字符串和输入表列和scanf函数相似。 【例】fscanf(fp,"%5d",&a[i]); 说明: 函数的返回值若为EOF,表明格式化读错误;否则读数据成功。 fscanf(文件指针,"格式字符串",输入表列);
27
fprintf(文件指针,"格式控制字符串",输出项列表);
9.3 文件的读写 格式读写函数 (2)格式化写函数fprintf 功能:把格式化的数据写到指定文件中 fprintf与printf功能相似,区别在于fprintf是向文件中输出,而printf是向屏幕输出。 函数调用的一般形式: 其中,格式控制字符串和输出项列表和printf函数相似。 【例】 fprintf(fp,"%5d",a[i]); 说明: 函数的返回值为实际写入文件中的字符个数(字节数); 若写错误,则返回一个负数。 fprintf(文件指针,"格式控制字符串",输出项列表);
28
9.3 文件的读写 例9-3 随机产生20个[10,99]之间的整数,以每行5个数据输出到文本文件c:\data.txt中,要求每个数据占5个宽度,并且数据之间用逗号分隔。然后将其读出按升序排序后,按同样格式追加写在原文件后,与原数据之间空出2行。 编程分析: 采用模块化程序设计 将产生数据、将数据输出到文件、从文件中读取数据,排序和追加数据到文件分别写成GetData( )、PutDataToFile( )、GetDataFormFile( )和sort( )、AppendDataToFile( )函数
29
9.3 文件的读写 void main() { int a[20],i; GetData(a,20);
PutDataToFile(a,20); /*调用scandata()函数将数据读入到数组a中*/ GetDataFormFile(a,20); sort(a,20); /*调用sort()函数将数组a的数据排序*/ /*调用AppedDataToFile( ) 函数将排序后的数组a的数据写入到文件中*/ AppendDataToFile(a,20); } void GetData(int a[],int n) { int i; srand(time(NULL)); /* 初始化随机种子数 */ for(i=0;i<n;i++) a[i]=(rand()%90)+10; /* 产生[10,99]的随机整数 */ 电脑的随机数都是伪随机,也就是通过一定的算法得出一个数列,然后每 rand()一次就取一个数。 而srand()的功能就是就是设置产生随机数的公式的参数(随机数种子),如果使用相同的种子,那么得到的随机数也就是相同的。自然,如果使用不同的种子,得出的随机数序列也是不同的。不同的种子会得到 固定 的 不同的随机数序列 。 为了防止随机数每次重复常常使用系统时间来初始化
30
9.3 文件的读写 void PutDataToFile(int a[],int n) { int i;
OpenFile("c:\\data.txt","w"); for(i=0;i<n;i++) { if(i%5==0) fprintf(fp,"%5d",a[i]); else fprintf(fp,",%5d",a[i]); if((i+1)%5==0) fprintf(fp,"\n"); } fclose(fp); void GetDataFormFile(int a[],int n) /* 从文件读数据函数 */ OpenFile("c:\\data.txt","r"); { if(i%5==0) fscanf(fp,"%5d",&a[i]); /* 每1行的第1个数据前不用逗号 */ fscanf(fp,",%5d",&a[i]);
31
9.3 文件的读写 void sort(int a[],int n) { int i,j,k,t;
for(i=0;i<n-1;i++) { k=i; for(j=i+1;j<n;j++) if(a[k]>a[j])k=j; t=a[i]; a[i]=a[k]; a[k]=t; } void OpenFile(char *file,char *pr) { if((fp=fopen(file,pr))==NULL) /* 打开文件失败 */ { printf("Cannot open file,stike any key to exit!"); exit(0); /* 退出程序 */
32
9.3 文件的读写 void AppendDataToFile(int a[],int n) /*追加数据函数 */ { int i;
OpenFile("c:\\data.txt","a"); /* 打开文件失败 */ fprintf(fp,"\n\n"); /* 输出2个空行 */ for(i=0;i<n;i++) { if(i%5==0) fprintf(fp,"%5d",a[i]); else fprintf(fp,",%5d",a[i]); if((i+1)%5==0) fprintf(fp,"\n"); } fclose(fp);
33
9.3 文件的读写 #include <stdio.h> #define STUNUM 5 /*代表学生人数*/
例9-4 从键盘输入5个学生的学号、姓名和成绩,将学生数据写入文件,然后再从文件中将这些信息读出显示在屏幕上。 #include <stdio.h> #define STUNUM 5 /*代表学生人数*/ #define COURSENUM 3 /*代表课程门数*/ struct student { int sno; /*学号*/ char sname[10]; /*学生姓名*/ int score[COURSENUM]; /*每个学生的三门课成绩*/ }stu1[STUNUM],stu2[STUNUM];
34
9.3 文件的读写 void main() { FILE *fp; int i,j;
if((fp=fopen("c:\\stu.txt","w+"))==NULL) printf("File could not be opened!\n"); exit(0); } printf("input data:\n"); for(i=0;i<STUNUM;i++) /*从键盘输入学生数据*/ scanf("%d",&stu1[i].sno); scanf("%s ",stu1[i].sname); for(j=0;j<COURSENUM;j++) scanf("%d",&stu1[i].score[j]);
35
9.3 文件的读写 for(i=0;i<STUNUM;i++) /*学生数据写入文件中*/ {
fprintf(fp,"%d,",stu1[i].sno); fprintf(fp,"%s,",stu1[i].sname); for(j=0;j<COURSENUM;j++) fprintf(fp,"%d,",stu1[i].score[j]); } rewind(fp); /*文件的位置指针移动到文件开始处*/ for(i=0;i<STUNUM;i++) /*将文件中学生数据读入程序中*/ fscanf(fp,"%d,",&stu2[i].sno); fscanf(fp,"%s,",stu2[i].sname); fscanf(fp,"%d,",&stu2[i].score[j]);
36
9.3 文件的读写 printf("\nsno\tsname\t\tscores\n");
for(i=0;i<STUNUM;i++) /*将读出的数据显示在屏幕上*/ { printf("%d\t",stu2[i].sno); printf("%s\t",stu2[i].sname); for(j=0;j<COURSENUM;j++) printf("%d\t",stu2[i].score[j]); printf("\n"); } fclose(fp);
37
fread(buffer,size,count,fp);
9.3 文件的读写 数据块读写函数 (1)读取数据块函数fread 功能:从指定文件中读取若干个数据块到程序中 函数调用的一般形式为: 参数buffer是一个指针,表示存放输入数据的内存存储地址; 参数size表示一个数据块的字节数; 参数count表示要读写的数据块块数。 fread(buffer,size,count,fp);
38
fwrite(buffer,size,count,fp);
9.3 文件的读写 数据块读写函数 (2)写数据块函数fwrite 功能:将若干个数据块写入到指定的文件中 函数调用的一般形式为: 参数buffer是一个指针,表示存放输出数据的内存存储地址; 参数size表示一个数据块的字节数; 参数count表示要读写的数据块块数。 fwrite(buffer,size,count,fp);
39
9.3 文件的读写 例9-5 改写例9-4使用数据块读写函数从键盘输入5个学生的学号、姓名和成绩,将学生数据写入文件,然后再从文件中将这些信息读出显示在屏幕上。 #include <stdio.h> #define STUNUM /*代表学生人数*/ #define COURSENUM /*代表课程门数*/ struct student { int sno; /*学号*/ char sname[10]; /*学生姓名*/ int score[COURSENUM]; /*每个学生的3门课成绩*/ }stu1[STUNUM],stu2[STUNUM];
40
9.3 文件的读写 void main() { FILE *fp; int i,j;
if((fp=fopen("c:\\stu.dat","wb+"))==NULL) /*二进制模式打开文件读和写*/ { printf("File could not be opened!\n"); exit(0); } printf("input data:\n"); for(i=0;i<STUNUM;i++) /*从键盘输入学生数据*/ scanf("%d,",&stu1[i].sno); scanf("%s ",stu1[i].sname); for(j=0;j<COURSENUM;j++) scanf("%d,",&stu1[i].score[j]);
41
9.3 文件的读写 fwrite(stu1,sizeof(struct student), STUNUM,fp);
/*学生数据写入文件中*/ rewind(fp); /*文件的位置指针移动到文件开始处*/ fread(stu2,sizeof(struct student), STUNUM,fp); /*将文件中数据读入程序中*/ printf("\nsno \t\t\tsname\tscores \n"); for(i=0;i<STUNUM;i++) /*将读出的数据显示在屏幕上*/ { printf("%d\t",stu2[i].sno); printf("%s\t",stu2[i].sname); for(j=0;j<COURSENUM;j++) printf("%d\t",stu2[i].score[j]); printf("\n"); } fclose(fp);
42
9.3 文件的读写 随机读写文件 前面的文件读写函数都是以顺序的方式操作的,如果用户希望直接读取文件中某一部分的信息,必须从文件头开始读,直到要求的文件读写位置再进行操作,这显然不方便。 为了解决这个问题,可以移动文件内部的位置指针到需要读写的位置,再进行读写,这种读写方式称为随机读写。 随机读写最常用于二进制文件。 实现随机读写的关键是按要求移动位置指针,这称为文件的定位。 C语言提供了一组文件的随机读写函数,可以将文件读写位置指针定位在所要求读写的地方,从而实现随机读写。
43
9.3 文件的读写 位移量(以起始点为基点,移动的字节数) >0 向后移动; <0 向前移动; =0保持不动 fseek函数 函数原型:int fseek(FILE *stream, long offset, int fromwhere) 功能:将文件的读写位置指针设置到特定的位置 返回值:成功,返回0;失败,返回非0值 起始点 文件开始 SEEK_SET 0 文件当前位置 SEEK_CUR 1 文件末尾 SEEK_END 2 例 fseek(fp,100L,0); fseek(fp,50L,1); fseek(fp,-10L,2);
44
ftell函数:long ftell(FILE *stream);
9.3 文件的读写 ftell函数:long ftell(FILE *stream); 返回文件读写位置指针的当前值,这个值是从文件头开始算起到文件指针位置的字节数,返回的数为长整型数; 若返回-1,表明出现错误。 rewind函数:int rewind(FILE *stream); 用于将文件内部的读写位置指针移动到文件的开始处; 成功时返回0;否则,返回非0值。
45
9.3 文件的读写 例9-6 从例9-5所建立的文件c:\stu.dat中读取第2个学生的所有信息并显示在屏幕上。
#include <stdio.h> #define STUNUM 5 /*代表学生人数*/ #define COURSENUM 3 /*代表课程门数*/ struct student { int sno; /*学号*/ char sname[10]; /*学生姓名*/ int score[COURSENUM]; /*每个学生的三门课成绩*/ }stu; void main() FILE *fp; int i; if((fp=fopen("c:\\stu.dat","rb"))==NULL) { printf("File could not be opened!\n"); exit(0); }
46
9.3 文件的读写 fseek(fp,1L*sizeof(struct student),SEEK_SET);
/* 文件位置指针移动到第一个学生数据之后 */ fread(&stu,sizeof(struct student),1,fp); /*将文件中该学生数据读入变量中*/ printf("\nsno\tscores\t\t\tsname\n"); /*将读出的学生数据显示在屏幕上*/ printf("%d\t",stu.sno); printf("%s\n",stu.sname); for(i=0;i<COURSENUM;i++) printf("%d\t",stu.score[i]); fclose(fp); } 本章结束
47
9.4 应用举例 9.4.1 文件的加密和解密 例9-8 设计一个对指定文件进行加密和解密的程序,密码和文件名由用户输入。 【加密方法】
例9-8 设计一个对指定文件进行加密和解密的程序,密码和文件名由用户输入。 【加密方法】 以二进制打开文件,将密码中每个字符的ASCII码值与文件的每个字节进行异或运算,然后写回原文件原位置即可。这种加密方法是可逆的,即对明文进行加密得到密文,用相同的密码对密文进行加密就得到明文。此方法适合各种类型的文件加密解密。 下面用两种方法实现对文件的加密和解密。
48
9.4 应用举例 方法一:程序运行后,用户在提示下输入文件名和密码。
编辑分析:由于涉及到文件的读和写,采用逐个字节从原文件中读出,加密后写入一个新建的临时文件,最后,删除原文件,把临时文件改名为原文件名,完成操作。 #include <stdio.h> #include <string.h> char encrypt(char f, char c) /*字符加密函数*/ { return f ^ c; /*返回两字符ASCII码按位做异或运算的结果*/ }
49
9.4 应用举例 void main() { FILE *fp, *fp1;
char fn[40], *p=fn, ps[10], *s=ps; char ch; char *tm= "C:\\temp.tmp"; //临时文件名 printf("Input the path and filename:"); gets(p); //输入文件名 *tm=*p; //确保临时文件和要加密的文件在同一盘内 // 判断文件是否能打开,临时文件是否能建立 if((fp=fopen(p,"rb"))==NULL||(fp1=fopen(tm,"wb"))==NULL) { printf("Cannot open file strike any key exit!"); exit(0); // 退出 } printf("Input the password:"); gets(s); // 输入密码
50
9.4 应用举例 ch=fgetc(fp); while(!feof(fp)) //当原文件没读完时
{ s=ps; //从密码的第一个字符开始处理 while(*s!= '\0') ch=encrypt(ch, *s++); //调用函数加密,让s指向下一个密码字符 fputc(ch, fp1); // 把加密后的字节写入临时文件 ch=fgetc(fp); // 读入一个字节 } fclose(fp); fclose(fp1); remove(p); // 删除原文件 rename(tm, p); // 把临时文件改名为原文件名
51
9.4 应用举例 #include <stdio.h> #include <string.h>
方法二:将要加密的文件和密码,通过命令行参数传递给程序,并且加密解密过程对文件的读写采有随机读写,不建立临时文件,程序代码如下: #include <stdio.h> #include <string.h> char encrypt(char f,char c) //字符加密函数 { return f ^ c; //返回两字符ASCII码按位做异或运算的结果 }
52
9.4 应用举例 void main(int argc,char *argv[])//main函数带两个参数 { FILE *fp;
char *s,ch; if(argc!=3) //如果输入的命令行参数数目不正确 { printf("Parameter Error! strike any key exit!"); exit(0); //退出 } if((fp=fopen(argv[1],"rb+"))==NULL) { printf("Cannot open file strike any key exit!"); ch=fgetc(fp);
53
9.4 应用举例 while(!feof(fp)) { s=argv[2]; //从让s指向密码的字符串的首地址
while(*s!= '\0') ch=encrypt(ch, *s++); //调用函数对s指向的字符加密,再让s指向下一个密码字符 fseek(fp,-1L,SEEK_CUR); //将位置指针从当前位置向前移1个字节 fputc(ch, fp); //把加密后的字节写入文件原来的位置 fseek(fp,1L,SEEK_CUR); //将位置指针从当前位置向后移1个字节 ch=fgetc(fp); //读入一个字节 } fclose(fp);
54
9.4 应用举例 设程序经过编译连接生成可执行的文件名为encfile.exe。加密时,命令格式为: encfile文件名 密码
【例】encfile c:\myfile.dat apple 功能: 对c盘根目录下的文件myfile.dat以密码apple进行加密,若再次执行相同的命令,则是对myfiel.dat进行解密。 命令行参数argc为3,argv[0]、argv[1]、argv[2]分别为encfile、c:\myfile.dat和apple。
55
9.4 应用举例 9.4.2 文件的拆分和连接 例9-9 将文件file1.txt的内容从中间分成两个部分,前一部分保留在file1.txt,后一部分输出到file2.txt保存。 编程分析: 先求文件的长度,通过其循环控制将file1.txt文件的前一半内容写入到一个临时文件中,后一半内容写入到file2.txt文件中。然后将原file1.txt文件删除,最后将临时文件更名为file1.txt。
56
9.4 应用举例 #include <stdio.h> void main()
{ FILE *fp1,*fp2,*fp_temp; long len; int i; if((fp1=fopen("C:\\file1.txt","r"))==NULL) { printf("File could not be opened!\n"); exit(0); /*若打开失败,结束程序*/ } fseek(fp1,0L,SEEK_END); /*移动file1文件位置指针到文件尾*/ len=ftell(fp1); /*求file1文件尾到文件头的字节数*/ if((fp2=fopen("C:\\file2.txt","w"))==NULL) exit(0); /*若打开失败,结束程序*/
57
9.4 应用举例 if((fp_temp=fopen("C:\\temp.txt","w"))==NULL)
{ printf("File could not be opened!\n"); exit(0); /*若打开失败,结束程序*/ } rewind(fp1); /*file1文件位置指针移到文件头*/ for(i=1;i<=len/2;i++) /*file1的前一半内容写入临时文件temp*/ fputc(fgetc(fp1),fp_temp); for(;i<=len;i++) /*file1的后一半内容写入file2*/ fputc(fgetc(fp1),fp2); fclose(fp1); /*关闭文件*/ fclose(fp2); /*关闭文件*/ fclose(fp_temp); /*关闭文件*/ remove("c:\\file1.txt"); /*删除file1文件*/ rename("c:\\temp.txt","c:\\file1.txt"); /*重命名文件temp为文件file1*/
58
9.4 应用举例 例9-10 将C盘根目录下的文件file2.txt的内容连接在file1.txt后面。
#include <stdio.h> void main() { FILE *fp1,*fp2; char ch; if((fp1=fopen("C:\\file1.txt","a"))==NULL) { /*打开一个文件file1.txt追加*/ printf("File could not be opened!\n"); exit(0); /*若打开失败,结束程序*/ } if((fp2=fopen("C:\\file2.txt","r"))==NULL) { /*打开一个文件file2.txt只读*/
59
9.4 应用举例 while(!feof(fp2)) /*当fp2文件没有结束*/ { ch=fgetc(fp2); /*读取一个字符*/
fputc(ch,fp1); /*写一个字符*/ } fclose(fp1); fclose(fp2); /*关闭文件*/
60
本章小结 文本文件和二进制文件的区别; 缓冲文件系统; 文件指针的概念和定义; 文件的打开和关闭; 文件的字符、字符串、格式化、数据块输入输出函数; 文件的随机读写函数。
61
本章书面作业 P265 习题一、二、三、四
Similar presentations