第 13 章 文 件

63
13.1 文文文文 13.2 文文文文文文 13.3 文文文文文文文文 13.4 文文文文文 13.5 文文文文文 13.6 文文文文文 13.7 文文文文文文文文 文文 文 13 文

Upload: huey

Post on 16-Mar-2016

90 views

Category:

Documents


5 download

DESCRIPTION

第 13 章 文 件. 13.1  C文件概述 13.2  文件类型指针 13.3  文件的打开与关闭 13.4  文件的读写 13.5  文件的定位 13.6  出错的检测 13.7  文件输入输出小结 习题. 13.1 C 文件概述. 为什么要使用文件 ? 断电后数据不丢失 操作系统是以文件为单位对数据进行管理的 在使用文件之前需要了解 目录结构 文件读写方式. 目录结构 ( Directory Tree ). 操作系统的文件系统都采用树型的目录结构 绝对路径 (Absolute Path) 完整的描述文件位置的路径就是绝对路径 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 13 章  文  件

13.1 C文件概述13.2 文件类型指针13.3 文件的打开与关闭13.4 文件的读写13.5 文件的定位13.6 出错的检测13.7 文件输入输出小结习题

第 13 章 文 件

Page 2: 第 13 章  文  件

为什么要使用文件 ? 断电后数据不丢失

操作系统是以文件为单位对数据进行管理的 在使用文件之前需要了解

目录结构 文件读写方式

13.1   C 文件概述

Page 3: 第 13 章  文  件

目录结构 (Directory Tree) 操作系统的文件系统都采用树型的目录结构 绝对路径 (Absolute Path)

完整的描述文件位置的路径就是绝对路径 D:\VCProjects\sample\main.cpp

相对路径 (Relative Path) 为什么要使用相对路径?“可移植性” 相对于什么? 相对于当前路径 如果当前路径是: D:\VCProjects 则: sample\main.cpp “../” 表示上一级目录

Page 4: 第 13 章  文  件

根据数据的组织形式 , 文件可分为: 二进制文件 (Binary File)

把数据按其在内存中的存储形式存放在磁盘上 , .exe .doc .mp3… 整数 10000, 在内存中占 2 个字节 , 按二进制形式 , 也占 2 个字节 一个字节并不对应一个字符 , 不能直接输出字符形式。一般中间结果数据需要暂时保存在外存上以后又需要输入到内存的 , 常用二进制文件保存

ASCII 文件:又称文本 (text) 文件 为了便于使用 , 一个字符用一个字节的 ASCII 代码存放 如果有一个整数 10000, 占 5 个字节 所有内容都是可打印字符 , .c .txt .h .htm… 一般占存储空间较多 , 而且要花费转换时间 ( 二进制形式与 ASCII 码间的转换 )

Page 5: 第 13 章  文  件
Page 6: 第 13 章  文  件

每个被使用的文件都在内存中开辟一个区 , 用来存放文件的有关信息 ( 如文件的名字、文件状态及文件当前位置等 ) 。这些信息是保存在一个由系统定义的 FILE 结构体变量中。 Turbo C 在 stdio.h 文件中有以下的文件类型声明:

13.2  文件类型指针

Page 7: 第 13 章  文  件

typedef   struct{

short level; /* 缓冲区“满”或“空”的程度 */unsigned flags; /* 文件状态标志 */char fd; /* 文件描述符 */unsigned char hold; /* 如无缓冲区不读取字符 */short bsize; /* 缓冲区的大小 */unsigned char *baffer;/* 数据缓冲区的位置 */unsigned char *curp; /* 指针 , 当前的指向 */unsigned istemp; /* 临时文件 , 指示器 */short token; /* 用于有效性检查 */    

}FILE;

Page 8: 第 13 章  文  件

FILE   f[5]; 定义了一个结构体数组 f, 它有 5 个元素 , 可以用来存放 5 个文件的信息。 FILE   fp; 可以使文件指针 fp 指向某一个文件的结构体变量 , 从而通过该结构体变量中的文件信息能够访问该文件。也就是说 , 通过文件指针变量能够找到与它相关的文件。

Page 9: 第 13 章  文  件

13.3.1  文件的打开 (fopen函数 ) fopen函数的调用方式通常为 :

FILE *fp;fp=fopen( 文件名 , 使用文件方式 );

fp=fopen("a1", "r");

13.3  文件的打开与关闭

Page 10: 第 13 章  文  件

文件使用方式        意 义“ rt”   只读打开一个文本文件 , 只允许读数据 “wt”   只写打开或建立一个文本文件 , 只允许写数据“ at”   追加打开一个文本文件 , 并在文件末尾写数据“ rb”   只读打开一个二进制文件 , 只允许读数据“wb”   只写打开或建立一个二进制文件 , 只允许写数据“ ab”   追加打开一个二进制文件 , 并在文件末尾写数据“ rt+”  读写打开一个文本文件 , 允许读和写“wt+”  读写打开或建立一个文本文件 , 允许读写“ at+”  读写打开一个文本文件 , 允许读 , 或在文件末追加数据“ rb+”  读写打开一个二进制文件 , 允许读和写 “wb+” 读写打开或建立一个二进制文件 , 允许读和写“ ab+” 读写打开一个二进制文件 , 允许读 , 或在文件末追加数据 r(read): 读w(write): 写a(append): 追加t(text): 文本文件 , 可省略不写b(binary): 二进制文件+: 读和写

Page 11: 第 13 章  文  件

(1) 如果打开一个不存在的文件用于写或追加 , 该文件将被创建(如果可能的话)。 (2) 当以写方式打开一个已存在的文件时 , 该文件原来的内容将被覆盖。但是 , 如果以追加方式打开一个文件 , 则该文件原来的内容保留不变。 (3) 读一个不存在的文件会导致错误 , 其他一些操作也可能导致错误 , 比如试图读取一个无读取权限的文件。如果发生错误 , fopen将返回NULL 。

if   (NULL==(fp=fopen("file1", "r"))){

printf("cannot open this file\n"); exit(0);}

说明:

Page 12: 第 13 章  文  件

(4) 在向计算机输入文本文件时 , 将回车换行符转换为一个换行符 , 在输出时把换行符转换成为回车和换行两个字符。在用二进制文件时 , 不进行这种转换 , 在内存中的数据形式与输出到外部文件中的数据形式完全一致 , 一一对应。 (5) 在程序开始运行时 , 系统自动打开 3 个标准文件:标准输入、标准输出、标准出错输出。通常这 3 个文件都与终端相联系。因此以前我们所用到的从终端输入或输出都不需要打开终端文件。系统自动定义了 3 个文件指针 stdin 、 stdout和 stderr, 分别指向终端输入、终端输出和标准出错输出也从终端输出 ) 。如果程序中指定要从 stdin 所指的文件输入数据 , 就是指从终端键盘输入数据。

Page 13: 第 13 章  文  件

应该养成在程序终止之前关闭所有文件的习惯 , 如果不关闭文件将会丢失数据。 因为 , 在向文件写数据时 , 是先将数据输到缓冲区 , 待缓冲区充满后才正式输出给文件。如果当数据未充满缓冲区而程序结束运行 , 就会将缓冲区中的数据丢失。用fclose函数关闭文件 , 可以避免这个问题 , 它先把缓冲区中的数据输出到磁盘文件 , 然后才释放文件指针变量。

fclose函数调用的一般形式为: fclose( 文件指针 ); 例如: fclose(fp); 关闭操作执行正确 , 返回 0;否则返回 EOF(-1) 。

13.3.2  文件的关闭 (fclose函数 )

Page 14: 第 13 章  文  件

13.4.1   fputc函数和 fgetc函数 (putc 、 fgetc) 1.   fputc函数 int fputc(int ch, FILE *fp); 把字符 ch 写到 fp 所指向的文件中。 如果输出成功则返回输出的字符 ; 如果输出失败 , 则返回一个 EOF(-1) 。 EOF 是在 stdio.h 文件中定义的符号常量 , 值为 -1 。 putchar(c) 是在 stdio.h 文件中定义的宏:#define   putchar(c)   fputc(c, stdout) #define putc(ch, fp) fputc(ch, fp) #define getc(fp) fgetc(fp)

13.4 文件的读写

Page 15: 第 13 章  文  件

int fgetc(FILE *fp) 从指定的文件返回下一个字符 , 该文件必须是以读或读写方式打开的。 如果遇到文件结束符 , 函数返回一个文件结束标志 EOF(-1) 。 如果想从一个磁盘文件顺序读入字符并在屏幕上显示出来 , 可以:

ch=fgetc(fp);while(!feof(fp)){putchar(ch);ch=fgetc(fp);}

2. fgetc函数

Page 16: 第 13 章  文  件

例13.1 从键盘输入一些字符, 逐个把它们送到磁盘上去, 直到输入一个“#”为止。void main(){

FILE *fp;char ch,filename[10];scanf("%s",filename);if((fp=fopen(filename,"w"))==NULL){printf("cannot open file\n");exit(0);}

3.   fputc和 fgetc函数使用举例

Page 17: 第 13 章  文  件

ch=getchar();/*此语句用来接收在执行scanf语句时最后输入的回车符*/ch=getchar();/* 接收输入的第一个字符*/while(ch!='#'){fputc(ch, fp);putchar(ch);ch=getchar();}fclose(fp);

}

Page 18: 第 13 章  文  件

运行情况如下:file1. c ( 输入磁盘文件名 )computer and c# ( 输入一个字符串 )computer and c ( 输出一个字符串 )

Page 19: 第 13 章  文  件

例 13.2将一个磁盘文件中的信息复制到另一个磁盘文件中。#include <stdio.h>void main(){

FILE *in, *out;char infile[10], outfile[10];printf("Enter the infile name : \n");scanf("%s", infile);printf("Enter the outfile name : \n");scanf("%s", outfile);

Page 20: 第 13 章  文  件

if((in=fopen(infile, "r"))==NULL){printf("cannot open infile\n");exit(0);}if((out=fopen(outfile, "w"))==NULL){printf("cannot open outfile\n");exit(0);}while(!feof(in))fputc(fgetc(in), out);fclose(in);fclose(out);

}

Page 21: 第 13 章  文  件

运行情况如下:Enter the infile name :file1. c ( 输入原有磁盘文件名 )Enter the outfile name :file2. c   ( 输入新复制的磁盘文件名 ) 也可以用此程序来复制一个二进制文件 , 只需将两个 fopen函数中的“ r”和“w” 分别改为“ rb”和“wb”即可。 也可以在输入命令行时把两个文件名一起输入。这时要用到 main函数的参数。程序可改为

Page 22: 第 13 章  文  件

void main(int argc, char*argv[]){

FILE *in, *out;if (argc!=3){printf("You forgot to enter a filename\n");exit(0);}if ((in=fopen(argv[1], "r"))==NULL){printf("cannot open infile\n");exit(0);}if ((out=fopen(argv[2], "w"))==NULL){printf("cannot open outfile\n");exit(0);}

Page 23: 第 13 章  文  件

while(!feof(in))fputc(fgetc(in), out);fclose(in);fclose(out);

}

Page 24: 第 13 章  文  件

常常要求一次读入一组数据 (例如 , 一个实数或一个结构体变量的值 ), ANSI C 标准提出设置两个函数 (fread和 fwrite), 用来读写一个数据块。 它们的一般调用形式为fread(buffer, size, count, fp);fwrite(buffer, size, count, fp); buffer :是一个指针。对 fread 来说 , 它是读入数据的存放地址。对 fwrite 来说 , 是要输出数据的地址 ( 以上指的是起始地址 ) 。 size :要读写的字节数。 count :要进行读写多少个 size 字节的数据项。 fp :文件型指针。 如果 fread 或 fwrite调用成功 , 则函数返回值为 count 的值。

13.4.2   fread函数和 fwrite函数

Page 25: 第 13 章  文  件

如果文件以二进制形式打开 , 用 fread和 fwrite函数就可以读写任何类型的信息 , 如: fread(f, 4, 2, fp); 其中 f 是一个实型数组名。一个实型变量占 4个字节。 这个函数从 fp 所指向的文件读入 2次 ( 每次4个字节 ) 数据 , 存储到数组 f 中。

Page 26: 第 13 章  文  件

如果有一个如下的结构体类型:#define SIZE 4struct student_type{

char name[10];int num;int age;char addr[15];

}stud[SIZE];

Page 27: 第 13 章  文  件

例 13.3 从键盘输入 4个学生的有关数据 , 然后把它们转存到磁盘文件上去。void save(){

FILE *fp;int i;if ((fp=fopen("c:\\a.txt", "wb"))==NULL){printf("cannot open file\n");return;}for (i=0; i<SIZE; i++){if (fwrite(&stud[i], sizeof(struct student_type), 1, fp)!=1)printf("file write error\n");}fclose (fp);

}

Page 28: 第 13 章  文  件

void main(){

int i; for(i=0;i<SIZE;i++) scanf("%s%d%d%s", stud[i].name, &stud[i].num, &stud[i].age, stud[i].addr); save();}

Page 29: 第 13 章  文  件

void load(){

FILE *fp;int i;if ((fp=fopen("c:\\a.txt", "rb"))==NULL){printf("cannot open infile\n");return;}

Page 30: 第 13 章  文  件

for (i=0; i<SIZE; i++){if (fread(&stud[i], sizeof(struct student_type), 1, fp)!=1){if(feof(fp)){fclose (fp); return;}printf("file read error\n");}}fclose (fp);

}

Page 31: 第 13 章  文  件

void main(){

load();for (int i=0; i<SIZE; i++){printf("%s %d %d %s\n",stud[i].name, stud[i].num, stud[i].age, stud[i].addr);}save();

}

Page 32: 第 13 章  文  件

请注意输入输出数据的状况。从键盘输入4个学生的数据是 ASCII 码 , 也就是文本文件。在送到计算机内存时 , 回车和换行符转换成一个换行符。再从内存以“wb” 方式 ( 二进制写 ) 输出到“ stu_list” 文件 , 此时不发生字符转换 , 按内存中存储形式原样输出到磁盘文件上。在上面验证程序中 , 又用 fread函数从“ stu_list” 文件向内存读入数据 , 注意此时用的是“ rb”方式 , 即二进制方式 , 数据按原样输入 , 也不发生字符转换。也就是这时候内存中的数据恢复到第一个程序向 “ stu-list” 输出以前的情况。最后在验证程序中 , 用 printf函数输出到屏幕 , printf 是格式输出函数 , 输出 ASCII 码 , 在屏幕上显示字符。换行符又转换为回车加换行符。

Page 33: 第 13 章  文  件

如果企图从“ stu_list” 文件中以“ r” 方式读入数据就会出错。 fread和 fwrite函数一般用于二进制文件的输入输出。因为它们是按数据块的长度来处理输入输出的 , 在字符发生转换的情况下很可能出现与原设想的情况不同。 例如 , 如果写 fread(&stud[i], sizeof(struct student-type), 1, stdin);

Page 34: 第 13 章  文  件

 企图从终端键盘输入数据 , 这在语法上并不存在错误 , 编译能通过。如果用以下形式输入数据: Zhang 1001   10   room-101 … 由于 fread函数要求一次输入 29个字节 ( 而不问这些字节的内容 ), 因此输入数据中的空格也作为输入数据而不作为数据间的分隔符了。连空格也存储到 stud[i] 中了 , 显然是不对的。 这个题目要求的是从键盘输入数据 , 如果已有的数据已以二进制形式存储在一个磁盘文件“ stu-dat” 中 , 要求从其中读入数据并输出到“ stu-list” 文件中 , 可以编写一个 load函数 , 从磁盘文件中读二进制数据。

Page 35: 第 13 章  文  件

void load(  )    {FILE fp; int i; if((fp=fopen("stu-dat", "rb"))==NULL) {printf("cannot open infile\n"); return;} for(i=0;i<SIZE;i++) if(fread(&stud[i], sizeof(struct student-type), 1, fp)!=1)

Page 36: 第 13 章  文  件

{if(feof(fp)){fclose (fp); return;} printf("file read error\n"); }fclose (fp); }  将 load函数加到本题原来的程序文件中, 并将main函数改为main( )   {    load( );    save( );   }

Page 37: 第 13 章  文  件

13.4.3   fprintf函数和 fscanf函数 fprintf函数、 fscanf函数与 printf函数、 scanf函数作用相仿 , 都是格式化读写函数。只有一点不同:fprintf和 fscanf函数的读写对象不是终端而是磁盘文件。它们的一般调用方式为 fprintf( 文件指针 , 格式字符串 , 输出表列 );fscanf ( 文件指针 , 格式字符串 , 输入表列 );例如 : fprintf(fp, "%d, %6.2f", i, t); 它的作用是将整型变量 i和实型变量 t 的值按%d和%6.2f 的格式输出到 fp 指向的文件上。如果 i=3, t=4.5, 则输出到磁盘文件上的是以下的字符串:

Page 38: 第 13 章  文  件

3,  4.50 同样 , 用以下 fscanf函数可以从磁盘文件上读入 ASCII 字符: fscanf(fp, "%d, %f", &i, &t); 磁盘文件上如果有以下字符: 3,  4.5 则将磁盘文件中的数据 3送给变量 i, 4.5送给变量 t 。 用 fprintf和 fscanf函数对磁盘文件读写 , 使用方便 , 容易理解 , 但由于在输入时要将ASCII 码转换为二进制形式 , 在输出时又要将二进制形式转换成字符 , 花费时间比较多。因此 , 在内存与磁盘频繁交换数据的情况下 , 最好不用 fprintf和

Page 39: 第 13 章  文  件

fscanf函数 , 而用 fread和 fwrite函数。13.4.4 其他读写函数 1. putw和getw函数 大多数 C编译系统都提供另外两个函数: putw和getw, 用来对磁盘文件读写一个字 ( 整数 ) 。例如: putw(10, fp); 它的作用是将整数 10 输出到 fp 指向的文件。而 i=getw(fp); 的作用是从磁盘文件读一个整数到内存 , 赋给整型变量 i 。 如果所用的 C编译的库函数中不包括putw和getw函数 , 可以自己定义该两函数。 putw函数如下:

Page 40: 第 13 章  文  件

putw(int i, FILE *fp)   {char s;     s=(char*)&i; putc(s[0], fp);putc(s[1], fp); return(i);   } 当调用putw函数时 , 如果用“ putw(10, fp);”语句 , 形参 i得到实参传来的值10, 在 putw函数中将 i的地址赋予指针变量 s, 而 s 是指向字符变量的指针变量 , 因此s指向 i的第1 个字节 , s+1指向i 的第2个字节。由于 *(s+0)就是s[0], *(s+1)就是s[1], 因此 , s[0]、 s[1]分别对应i 的第1字节和第2个字节。由于

Page 41: 第 13 章  文  件

图 13.3

  *(s+0) 就是 s[0], *(s+1) 就是 s[1], 因此 , s[0] 、 s[1] 分别对应 i 的第 1 字节和第 2 字节。顺序输出 s[0] 、 s[1]就相当于输出了 i 的两个字节中的内容。见图 13.3 。

Page 42: 第 13 章  文  件

getw函数如下:getw(FILE *fp)    {char s; int i; s=(char *)&i; /*使s指向i的起始地址*/ s[0]=getc(fp);  s[1]=getc(fp); return(i);   } putw和getw并不是ANSI C标准定义的函数。但许多C编译都提供这两个函数, 但有的C编译可能不

Page 43: 第 13 章  文  件

 以 putw和getw命名此两函数 , 而用其他函数名 , 请用时注意。2.  读写其他类型数据 如果用 ANSI C提供的 fread和 fwrite函数 , 读写任何类型数据都是十分方便的。如果所用的系统不提供这两个函数 , 用户只好自己定义所需函数。例如 , 可以定义一个向磁盘文件写一个实数 ( 用二进制方式 ) 的函数 putfloat :putfloat(float num, FILE *fp)    {char s;

Page 44: 第 13 章  文  件

int count; s=(char *)&num; for(count=0;count<4;count++) putc(s[count], fp); } 同样可以编写出读写任何类型数据的函数。3.  fgets函数和fputs函数 fgets的作用是从指定文件读入一个字符串。如: fgets(str, n, fp); n为要求得到的字符, 但只从fp指向的文件输入n-1个字符, 然后在最后加一个‘\0’字符, 因此得到

Page 45: 第 13 章  文  件

 的字符串共有 n 个字符。把它们放到字符数组 str 中。如果在读完 n-1 个字符之前遇到换行符或 EOF, 读入即结束。 fgets函数返回值为 str 的首地址。 fputs函数的作用是向指定的文件输出一个字符串。如 :fputs("China", fp); 把字符串“ China” 输出到 fp 指向的文件。 fputs函数中第一个参数可以是字符串常量、字符数组名或字符型指针。字符串末尾的‘ \0’ 不输出。若输出成功 , 函数值为 0; 失败时 , 为 EOF 。 这两个函数类似以前介绍过的 gets和puts函数 , 只是 fgets和 fputs函数以指定的文件作为读写对象。

Page 46: 第 13 章  文  件

13.5  文 件 的 定 位 文件中有一个位置指针 , 指向当前读写的位置。如果顺序读写一个文件 , 每次读写一个字符 , 则读写完一个字符后 , 该位置指针自动移动指向下一个字符位置。如果想改变这样的规律 , 强制使位置指针指向其他指定的位置 , 可以用有关函数。13.5.1   rewind函数 rewind函数的作用是使位置指针重新返回文件的开头。此函数没有返回值。 例13.4有一个磁盘文件 , 第一次将它的内容显示在屏幕上 , 第二次把它复制到另一文件上。

Page 47: 第 13 章  文  件

#include<stdio.h>   main() {FILE fp1, *fp2; fp1=fopen("file1.c", "r"); fp2=fopen("file2.c", "w"); while(!feof(fp1)) putchar(getc(fp1)); rewind(fp1); while(!feof(fp1)) putc(getc(fp1), fp2); fclose(fp1);fclose(fp2); } 在第一次将文件的内容显示在屏幕以后, 文件file1.c的位置指针已指到文件末尾, feof的值为非零(真)。执行rewind函数, 使文件的位置指针重

Page 48: 第 13 章  文  件

 新定位于文件开头 , 并使 feof函数的值恢复为 0(假 ) 。13.5.2   fseek函数和随机读写 对流式文件可以进行顺序读写 , 也可以进行随机读写。关键在于控制文件的位置指针 , 如果位置指针是按字节位置顺序移动的 , 就是顺序读写。如果能将位置指针按需要移动到任意位置 , 就可以实现随机读写。所谓随机读写 , 是指读写完上一个字符 ( 字节 ) 后 , 并不一定要读写其后续的址? 字节 ), 而可以读写文件中任意所需的字符 ( 字节 ) 。 用 fseek函数可以实现改变文件的位置指针。

Page 49: 第 13 章  文  件

fseek函数的调用形式为 fseek   ( 文件类型指针 , 位移量 , 起始点 ) “起始点”用 0 、 1 或 2 代替 , 0 代表“文件开始” , 1 为“当前位置” , 2 为“文件末尾”。 ANSI C 标准指定的名字如表 13.2 所示。 “ 位移量”指以“起始点”为基点 , 向前移动的字节数。 ANSI C和大多数 C版本要求位移量是 long 型数据。这样当文件的长度大于64K时不致出问题。 ANSI C 标准规定在数字的末尾加一个字母L, 就表示是 long 型。 下面是 fseek函数调用的几个例子: fseek(fp, 100L, 0);将位置指针移到离文件头100 个字节处

Page 50: 第 13 章  文  件

fseek(fp, 50L, 1); 将位置指针移到离当前位置 50 个字节处 fseek(fp, -10L, 2); 将位置指针从文件末尾处向后退10 个字节 利用 fseek函数就可以实现随机读写了。 例13.5 在磁盘文件上存有 10 个学生的数据。要求将第 1 、 3 、 5 、7、9个学生数据输入计算机 , 并在屏幕上显示出来。 程序如下:#include<stdio.h>

Page 51: 第 13 章  文  件

   struct student-type   { char name[10]; int num; int age; char sex;   }stud[10];   main()   { int i; FILE *fp;

Page 52: 第 13 章  文  件

if((fp=fopen("stud -dat", "rb"))==NULL)    {printf("can not open file\n"); exit(0);} for(i=0;i<10;i+=2) { fseek(fp, i*sizeof(struct student-type), 0); fread(&stud[i], sizeof(struct student-type), 1, fp);

Page 53: 第 13 章  文  件

printf("%s %d %d %c\n", stud[i].name, stud[i].num, stud[i].age, stud[i].sex); } fclose(fp); }13.5.3   ftell函数 ftell函数的作用是得到流式文件中的当前位置 , 用相对于文件开头的位移量来表示。由于文件中的位置指针经常移动 , 人们往往不容易知道其当前位置。用 ftell函数可以得到当前位置。如果 ftell函数返回值为 -1L, 表示出错。例如:

Page 54: 第 13 章  文  件

i=ftell(fp);if(i==-1L)printf("error\n"); 变量 i 存放当前位置 , 如调用函数出错 ( 如不存在此文件 ), 则输出“ error” 。13.6 出 错 的 检 测 C 标准提供一些函数用来检查输入输出函数调用中的错误。13.6.1   ferror函数 在调用各种输入输出函数 ( 如 putc 、 getc 、 fread 、 fwrite 等 ) 时 , 如果出现错误 , 除了函数返回值有所反映外 , 还可以用 ferror函数检查。它的一般调用形式为 ferror(fp);

Page 55: 第 13 章  文  件

如果 ferror返回值为 0(假 ), 表示未出错。如果返回一个非零值 , 表示出错。应该注意 , 对同一个文件每一次调用输入输出函数 , 均产生一个新的 ferror函数值 , 因此 , 应当在调用一个输入输出函数后立即检查 ferror函数的值 , 否则信息会丢失。在执行 fopen函数时 , ferror函数的初始底远 梦 ? 。13.6.2   clearerr函数 它的作用是使文件错误标志和文件结束标志置为 0 。假设在调用一个输入输出函数时出现错误 , ferror函数值为一个非零值。在调用 clearerr(fp) 后 , ferror(fp) 的值变成0 。

Page 56: 第 13 章  文  件

只要出现错误标志 , 就一直保留 , 直到对同一文件调用 clearerr函数或 rewind函数 , 或任何其他一个输入输出函数。 文件这一章的内容是很重要的 , 许多可供实际使用的 C 程序都包含文件处理。本章只介绍一些最基本的概念 , 由于篇幅所限 , 不可能举复杂的例子。希望读者在实践中掌握文件的使用。

Page 57: 第 13 章  文  件

习题13.1 什么是文件型指针?通过文件指针访问文件有什么好处?13.2 对文件的打开与关闭的含义是什么?为什么要打开和关闭文件?13.3 从键盘输入一个字符串 , 将其中的小写字母全部转换成大写字母 , 然后输出到一个磁盘文件“ test”中保存。输入的字符串以“ !” 结束。13.4 有两个磁盘文件“ A”和“ B”, 各存放一行字母 , 今要求把这两个文件中的信息合并 ( 按字母顺序排列 ), 输出到一个新文件“ C” 中去。

Page 58: 第 13 章  文  件

13.5 有 5 个学生 , 每个学生有 3门课的成绩 , 从键盘输入以上数据 (包括学生号 , 姓名 , 三门课成绩 ), 计算出平均成绩 , 将原有数据和计算出的平均分数存放在磁盘文件“ stud” 中。13.6 将上题“ stud” 文件中的学生数据 , 按平均分进行排序处理 , 将已排序的学生数据存入一个新文件“ stu-sort” 中。13.7 将上题已排序的学生成绩文件进行插入处理。插入一个学生的 3门课成绩 , 程序先计算新插入学生的平均成绩 , 然后将它按成绩高低顺序插入 , 插入后建立一个新文件。

Page 59: 第 13 章  文  件

13.8 上题结果仍存入原有的“ stu sort” 文件而不另建立新文件。13.9 有一磁盘文件“ emploee”, 内存放职工的数据。每个职工的数据包括职工姓名、职工号、性别、年龄、住址、工资、健康状况、文化程度。今要求将职工名、工资的信息单独抽出来另建一个简明的职工工资文件。13.10 从上题的“职工工资文件”中删去一个职工的数据 , 再存回原文件。

Page 60: 第 13 章  文  件
Page 61: 第 13 章  文  件
Page 62: 第 13 章  文  件
Page 63: 第 13 章  文  件

实验 13.6 13.7