数据文件的使用(C语言笔记)
一、 输入输出的基本概念

数据在外部设备和内存之间的传递,我们称之为输入输出。
二、文件概念
在C语言中,“文件”的概念具有广泛的意义,它把和主机进行数据交换的输入输出设备都看作一个文件。即把实际的物理设备抽象为逻辑文件,它们也被称为设备文件。
如:
- 键盘作为标准输入文件,文件名
stdin - 显示器作为标准输出设备,文件名
stdout,标准错误输出文件stderr - 打印机也可以作为输出文件,文件名
PRN
注:数值12345在ASCII文件中和二进制文件中的存放形式不同,整数 12345
i. 若存于文本文件中,占 5 个字节。
即存放 5 个 ASCII 字符(看成字符串),
本质上存储的是二进制值。
ii. 若存于二进制文件中,占 4 个字节(即内存映象)。
因为一个整数在内存中占 4 个字节,
本质上存储的仍是二进制值。
三、 缓冲
引入缓冲的目的是解决CPU的运行速度和外部设备操作速度不匹配的矛盾。提高计算机系统运行速度。以输出操作为例,在内存中开辟一个输出缓冲区,程序中的每次输出,不是立刻直接驱动并输出到外部设备上的,而是首先输出到缓冲区中,当缓冲区被写满或缓冲区不满但程序干涉时,才将缓冲区中的数据成批送往外部设备,这样可以减少对外部设备的驱动次数,提高输出速度。

四、文件的读写过程
(一) 预备知识
- 无论是文本文件还是二进制文件,文件都可以看成数据流,数据流由若干字节构成,以文件结束符EOF结尾。

- 在程序中要读写一个文件时,必须要通过指向文件的指针进行。
- 需知道待读写文件的文件名、文件类型、文件的操作方式(即读写方式)以及文件的读写位置指针等信息。
- 信息一般存放在一个文件信息区中,文件信息区的本质是一个结构体变量,其各个成员存放上述信息。
- 在缓冲文件系统中,对每个正在使用的文件,都要使用一个FILE类型的结构变量,该结构变量用于存放文件的有关信息,如:文件名、文件状态等。
- 在C语言中,无论是一般磁盘文件还是设备文件,都要通过文件结构的相应成员数据进行输入输出处理。
- 文件结构不需要用户定义,由系统事先定义好。
- 文件结构已由系统定义,在程序中若想读写一个文件,则首先必须为该文件建立一个信息区,用一个指针指向该信息区。
- 定义一个FILE类型(文件型)文件信息区指针(简称文件指针):
FILE * 文件型指针变量名;
例如: FILE *fp;
fp是一个指针变量,指向文件结构。如要同时使用多个文件时,必须有多个不同的文件指针。程序运行过程中,文件指针是指定待读写文件的唯一标识。
(二) 读写过程
FILE *file;
file=fopen(" "," ");
(其中第一个双引号里是文件地址,文件地址必须用 \ \ 隔开,不然会出错,第二个是打开类型)
打开类型汇总:
r :以只读方式打开文件,该文件必须存在。
r+ :以可读写方式
打开文件,该文件必须存在。
w :打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
w+: 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
a :以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
a+: 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留)
wb :只写打开或新建一个二进制文件;只允许写数据
wb+ :读写打开或建立一个二进制文件,允许读和写。
ab+ :读写打开一个二进制文件,允许读或在文件末追加数据。
rb+ :读写打开一个二进制文件,允许读写数据,文件必须存在。
一张好图:

注意:
1.当程序开始运行时,系统自动打开三个标准文件:
标准输入(文件指针stdin )
标准输出(文件指针stdout )
标准出错输出(文件指针stderr )
2.如果程序从stdin输入数据,则从键盘输入数据。
3.如果程序向stdout写数据,则写到屏幕上。
(三) 文件的打开与关闭
1.打开文件
——建立“文件信息区”,返回一个文件指针。
即通过指针建立用户程序与文件的联系,为文件开辟缓冲区。
FILE *fp;
fp=fopen(文件名,文件的使用方式);
文件名——字符串,可带路径
文件的使用方式——字符串
例:
fp = fopen("data.dat ","r");fp= fopen("d:\\c\\data.dat ","r");//以读方式打开正文文件 data.dat, 它事前应存在。若打开不成功,则 fopen( ) 函数返回空指针 NULL 。
一般以如下方式处理
#include
#include
int main()
{//一般如下处理FILE*fp;fp=fopen("d:\\data.dat","r");//以只读方式打开数据文件if (fp==NULL){printf("打不开");exit(1);//exit是系统函数,表示终止程序的运行}}
2.关闭文件
对文件读写完毕,要关闭该文件,释放信息区。
调用格式 fclose(fp); /* fp是文件指针 */
即切断文件和程序的联系,将文件缓冲区的内容写入磁盘,并释放文件指针。
注意:若文件关闭成功,则 fclose( ) 函数返回返回值为 0 。
若文件关闭失败,则返回非0值。
综上标准操作如下:
#include
#include
#include
int main()
{FILE*p=fopen("Contact.txt","r"); //打开文件输入文件地址,和打开方式if(p==NULL) //如果传入空指针则会报错{printf("%s", strerror(errno));//printf("%s", strerror(errno)) 用于输出当前的错误描述。//errno 是一个全局变量,它保存了最近一次发生的错误代码。strerror(errno) 将根据这个错误代码返回相应的错误描述字符串。}fclose(p); //关闭文件p=NULL; //防止变为野指针return 0;
}
五、 文件的读写
1. 文件顺序操作
对文件的操作(文件读写)必须按文件中字符的先后顺序进行,只能在操作了第i个字符后,才能操作第i+1个字符。
在对文件操作时,文件的位置指针由系统自动向后(文件尾方向)移动。
2. 文件读写函数
-
读写一个字符:fgetc函数和fputc函数。
-
读写一行字符串:fgets函数和fputs函数。
-
格式化读写:fscanf函数和fprintf函数。
-
“块”读写:fread函数和fwrite函数。
-
“字”(整数)读写:getw函数和putw函数。
-
ungetc函数用于退回一个字符到输入缓冲区中。
-
feof函数用于在文件的读写过程中,检测是否到达文件结束
| 文件I/O 函数 | 标准终端I/O函数 | 作用 |
|---|---|---|
| fgetc | getchar | 输入一个字符 |
| fputc | putchar | 输出一个字符 |
| fgets | gets | 输入一行字符串 |
| fputs | puts | 输出一行字符串 |
| fscanf | scanf | 格式化输入函数 |
| fprintf | printf | 格式化输出函数 |
(一) fgetc函数和fputc函数
用于读写一个字符,它们的函数原型是:
int fgetc(FILE *fp) ; /* 功能:从fp指定的文件中读入一个字符 */
int fputc(int c, FILE *fp) ; /* 功能:将字符c写入fp指定的文件中 */
(二)fgets函数和fputs函数
·fgets 原型为:
char * fgets(char *s, int n, FILE *fp) ; /* 功能:从fp 指定的文件中读入一行字符串,
最多读取n-1个字符,并把它们存放到字符数组s中,若在读入n-1个字符之前遇到换行符 ‘\n’ 或文件结束符EOF,则结束读入。
·fputs 原型为:
int fputs(const char *s, FILE *fp) ; /* 功能:将字符串s 写到fp指定的文件中 */
注意:
~fgets与gets的区别:
fgets将’\n’作为字符读入到字符串中,
而gets不把’\n’读入到字符串中。
~fputs与puts的区别:
fputs原样输出字符串,不增加输出’\n’;
而puts将字符串输出后,增加输出’\n’。
(三) fscanf函数和fprintf函数
fscanf 函数用于文件格式化的输入,原型为:
int fscanf(FILE *fp, const char *format, 输入量地址列表) ;
fprintf函数用于文件格式化输出,原型为:
int fprintf(FILE *fp, const char *format, 输出量列表) ;
参数fp 是文件指针,参数format是格式控制字符串。
与标准格式化输入输出函数scanf和printf的原型比较,多了第一个参数——文件指针,用于指定输入输出的数据文件。
其他的使用方式和 scanf 和 printf 没有区别。
scanf(“%d”,&x) 等价于 fscanf(stdin, “%d”, &x)
(四) feof函数
函数原型:
int feof(FILE *fp) ;/* 功能:判断fp指定的文件是否到达了文件结尾处 *//* 如果到达,则函数返回 “真”;否则返回“假” */
feof函数常用于循环读取文件内容的场景中,通过检查文件流的结束标志来确定是否已到达文件末尾。
例:以下是一个使用feof函数的示例代码,用于逐行读取文件内容并输出到控制台
#include int main() {FILE *fp;char line[100];fp = fopen("file.txt", "r");if (fp == NULL) {printf("无法打开文件\n");return 1;}while (!feof(fp)) {if (fgets(line, sizeof(line), fp) != NULL) {printf("%s", line);}}fclose(fp);return 0;
}
(五)ungetc函数的使用
函数原型如下:
int ungetc(int c, FILE *fp) ;
功能:将c字符退回到fp指定的输入数据流中。
例:假定文本文件data.txt的内容是字符流"ABCDEFG…",下面的函数读入其前三个字符,按逆序退回这三个字符,然后再读入前三个字符。通过本例,读者可以学习ungetc函数的使用,同时能够体会到文件缓冲区的意义。
int main( )
{ FILE *fp;char ch1, ch2, ch3; if((fp = fopen("data.txt", "r"))==NULL){ printf("Can not open data.txt!\n");exit(1); } ch1=fgetc(fp); ch2=fgetc(fp); ch3=fgetc(fp);printf("%c%c%c,", ch1, ch2, ch3);ungetc(ch1,fp); ungetc(ch2,fp); ungetc(ch3,fp);ch1=ch2=ch3='X';ch1=fgetc(fp); ch2=fgetc(fp); ch3=fgetc(fp);printf("%c%c%c\n", ch1, ch2, ch3);fclose(fp);return 0;
}
例1
从键盘输入以回车结尾的一行字符,将其写入文本文件:
# include /* 文件操作必须包含此头文件 */
# include
int main( )
{ FILE *fp; char filename[30], ch; /* filename存放文件名 */printf("Please enter the file name: ");gets(filename); /* 用标准输入函数输入目标文本文件名 */fp = fopen(filename, "w"); if(fp==NULL){ printf("Can not open file %s!\n", filename);exit(1); } while((ch=getchar( ))!='\n') /* A */fputc(ch, fp); /* B */fclose(fp);return 0;
}
例2
文本文件的复制
以下程序用于将一个源文件的内容复制到一个目标文件。
#include
#include
int main( )
{FILE *fp1, *fp2;char infile[30], outfile[30], ch; /* infile存放源文件名,outfile 存放目标文件 */printf("Please enter an input file name: ");gets(infile); /* 用标准输入函数输入源文件名 */fp1 = fopen(infile, "r"); if(fp1==NULL){ printf("Can not open file %s!\n", infile);exit(1); } printf("Please enter an output file name: ");gets(outfile); /* 用标准输入函数输入目标文件名 */fp2 = fopen(outfile, "w");if(fp2==NULL){ printf("Can not open file %s!\n", outfile);exit(2); }while((ch=fgetc(fp1))!=EOF) fputc(ch, fp2); fclose(fp1);fclose(fp2);return 0;
}
例3
从正文文件in.txt中读入数据到二维数组中,调用函数分别求该二维数组的主、辅对角线上的元素之和,然后将二维数组的数据以矩阵方式写入另一正文文件out.txt,最后写入求和结果。
int main( )
{void sum(int a[4][4], int *, int *); /* 函数原型说明 */FILE *fp1, *fp2;int a[4][4], i, j, sum1, sum2;if((fp1=fopen("dada.in", "r"))==NULL)/* 打开输入数据文件 */{ printf("Can'nt open dada.in!\n");exit(1); }if((fp2=fopen("data.out", "w"))==NULL)/* 打开输出数据文件 */{printf("Can'nt open data.out!\n");exit(2); }
for(i=0; i<4; i++)for(j=0; j<4; j++)fscanf(fp1, "%d", &a[i][j]); /* 从文件读元素值 */sum(a, &sum1, &sum2); /* 调用函数计算对角线元素之和 */for(i=0; i<4; i++){for(j=0; j<4; j++)fprintf(fp2, "%4d", a[i][j]); /* 写数组元素到文件 */fprintf(fp2, "\n");}fprintf(fp2, " sum1=%d\n sum2=%d\n", sum1, sum2); /* 写求和结果到文件 */ fclose(fp1);fclose(fp2);return 0;
}
void sum(int a[4][4], int *sum1, int *sum2)/* 通过指针带回多个计算结果 */
{int i;*sum1=*sum2=0;for(i=0; i<4; i++){*sum1 = *sum1 + a[i][i];*sum2 = *sum2 + a[i][3-i];}
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
