任务二 文件的读写
任务描述
文件创建打开之后就要对文件进行操作了,本任务就是在上一任务的基础之上,开始对文件进行使用和操作,这里的操作是指对磁盘文件的操作,操作的内容其实就是程序对文件进行读和写。
学习目标
掌握文件指针。
掌握如何实现字符的读写。
掌握如何实现字符串的读写。
掌握如何实现二进制问价的读写。
掌握如何实现随机文件的书写。
相关知识
12-2-1 文件的位置指针
当你正常打开了文件的时候,系统为每个文件设置了一个位置指针,该指针被称为文件位置指针,用来对文件进行读写控制。
在文件的顺序操作中,指针指向文件的开头,当读取文件的时候的,也是从第一个字符开始的,然后指针依次读取,一直到文件的结尾。为了让读者更好的理解文件的读取过程,接下来通过一个图例进行描述,如图12-5所示。
图12- 5 文件指针的位置
正因为指针可以指向文件任意为位置,在顺序读取的过程中也可以随机操作指针的位置,进行文件的随机读写。
12-2-2 字符的读写
在C语言中,针对字符的读写提供了fgetc()和fputc()函数,fgetc是从文件读一个字符,fputc是向文件写一个字符,这两个函数都是针对字符进行读写操作的。他们使用的方法如下。
1.使用fputc()函数实现向件写入一个字符
函数调用的形式为:fputc(字符量,文件指针);
例如:fputc(a,fp);
其意义是把字符a写入fp所指向的文件中。
使用说明:
(1)被写入的文件可以用写、读写、追加方式打开,用读写的方式会清除之后再写入,写入字符还是从文件首开始。
(2)每写入一个字符,文件内部位置指针向后移动一个字节。
(3)fputc函数有一个返回值,如写入成功则返回写入的字符,否则返回一个EOF。可由此来判断写入是否成功。
接下来我们通过一个实例来更深一步的了解fputc()函数的使用。
实例12- 2向文件写一个字符。
#include <stdio.h>
int main()
{
FILE *fp;
char ch='h';
fp = fopen("c:\\hello.txt", "w"); //打开一个文件,若文件不存在创建文件
if (fp == NULL) //文件不存在,则输出提示信息
{
printf("打开文件失败!\n");
}else{
fputc(ch, fp);
fclose(fp);
}
getchar();
return 0;
}
程序正常结束 ,接下来我们就C盘目录下找到hello.txt文件,打开文件里面的h字符已成功写入进去如图 12-6所示。
图12- 6 实例12-2 写入字符文件内容
2. 使用fgetc()函数实现从文件读取一个字符
函数调用的形式为:字符变量=fgetc(文件指针);
例如:ch=fgetc(fp);
其意义是从打开的文件fp中读取一个字符并存入ch中。
使用说明:在fgetc函数调用中,读取的文件必须是以读或读写方式打开的。
接下来我们通过一个实例来更深一步的了解fgetc()函数的使用。
实例12- 3 读取C盘目录下我们写入的文件字符。
#include <stdio.h>
int main() {
FILE *fp;
char ch;
fp = fopen("c:\\hello.txt", "r");
if (fp == NULL) {
printf("打开文件失败!\n");
}else{
ch = fgetc(fp);
printf("\n%c",ch);
fclose(fp);
}
getchar();
return 0;
}
运行结果如图所示 12-7所示,成功的把写入的h字符读出来了。
图12- 7 实例12-3运行结果
12-2-3 字符串的读写
单个字符不论是写入还是读取效率都比较差。为了提高效率,在C语言中还提供了fgets()和fputs()函数,fgets()用来从指定的文件读出一个字符串,fputs()函数实现写入一个字符串。这两个函数可以实现按行或按固定长度对文件进行读写操作,下面我们来学习两个函数。
1.使用puts()函数实现向件写入字符串
其调用形式为:fputs(字符串,文件指针)
其中“字符串”可以是字符串常量,也可以是字符数组名,或指针变量。
例如:fputs("nba",fp);其意义是把字符串“nba”写入fp所指的文件之中。
使用说明:
函数 fputs() 把字符串 s 写入到 fp 所指向的输出流中。如果写入成功,它会返
回一个非负值,如果发生错误,则会返回 EOF。
接下来我们通过一个实例来更深一步的了解fputs()函数的使用。
实例12- 4向文件写入字符串。
#include <stdio.h>
int main() {
FILE * file= fopen("c:\\abc.txt","w");
if(file==NULL){
printf("打开文件失败!");
}else{
fputs("我是来自C程序的字符串",file);
fclose(file);
}
getchar();
return 0;
}
程序正常结束 ,接下来我们就C盘目录下找到abc.txt文件,打开文件里面的”我是来自C程序的字符串”字符串已成功写入进去如图 12-8所示。
图12- 8 字符实例12-4写入的字符串
2. 使用fgets()函数实现从文件读取字符串
函数的调用的格式fgets(字符数组名,n,文件指针);
其中的n是一个正整数。表示从文件中读出的字符串不超过n-1个字符。在读入的最后一个字符后加上串结束标志\0。
接下来我们通过一个实例来更深一步的了解fgets()函数的使用。
实例12- 5 读取C盘目录下我们写入的文件字符串
#include <stdio.h>
int main() {
FILE * file= fopen("c://abc.txt","r");
if(file==NULL){
printf("文件打开失败!");
}else{
char ch[20]="0";
fgets(ch,20,file);
printf("%s",ch);
fclose(file);
}
getchar();
return 0;
}
运行结果如图12-9所示 ,成功的把写入的”我是来自C程序的字符串”字符读串出来了。
图12- 9 实例12-5运行结果
12-2-4 二进制文件的读写
前面的知识都是对文本文件的读写,但是在计算机的文件都是基于二进制文件存储的,二进制的数据就不能用文本文件的形式读取了,C语言使用fread()函数和fwrite()函数实现了对二进制数据进行读写。
使用格式如下:
fread ( void * ptr, size, count, FILE * fp );
其中,ptr指向保存结果的指针比如说数组地址,size每个数据类型的大小也就是字节数,count表示要读取数据的个数;fp文件指针函数,返回读取数据的个数。
fwrite ( const void * ptr, size, t count, FILE * stream );
其中,ptr指向保存数据的指针;size每个数据类型的大小也就是字节数,count表示要读取数据的个数;fp文件指针函数,函数返回写入数据的个数。
接下来我们通过一个案例来练习如何使用这两个函数,如何来对二进制读写。
实例12- 6 二进制读写。
#include <stdio.h>
int main() {
FILE * fp;
int buffer[] = {1, 2, 3, 4};
printf("把数组元素1,2,3,4写进文件里面\n");
if((fp = fopen ("test.txt", "wb"))!=NULL) {
fwrite (buffer , sizeof(int), 4, fp);
fclose (fp);
}else {
printf("文件读取失败");
}
printf("把数组元素从文件中读出来\n");
if((fp=fopen("test.txt","rb"))!=NULL) {
fread(buffer,sizeof(int),4,fp);
//循环读取
int i=0;
for ( i=0;i<4;i++)
printf("%d\t",buffer[i]);
fclose (fp);
} else {
printf("文件读取失败");
}
getchar();
return 0;
}
运行结果如图12-10所示 ,成功把1234写入之后也把其读了出来。
图12- 10 实例12-6的运行结果
12-2-5 按格式读写
实现对文件格式输入和输出的函数分别是fscanf()函数与fprintf()函数,看见这两个函数我们就会想起scanf()与printf()函数,但是它们操作的对象是不同的fscanf()函数与fprintf()函数是用来操作文件的。
1.使用fprintf()函数实现向件格式化写入数据
函数调用的形式为:fprintf(文件指针,格式字符串,参数列表);
函数来把一个字符串写入到文件中,例如: fprintf(file,"%s","hello c"); 指的是我向文件写入了hello c这个字符串。
2. 使用scanf()函数实现从文件格式化读取数据
函数调用的形式为:fscanf(文件指针,格式字符串,参数列表);
函数的作用是从文件中读取字符串, 但是在遇到第一个空格字符时,它会停止读取。
例如fscanf(file,"%d",&a);指的是从file文件中读取一个文件,保存到变量a中。
fprintf( )和fscanf( )函数对磁盘文件读写,使用方便,但由于在输入时要将ASCII码转换为二进制形式,在输出时又要将二进制形式转换为字符,花费时间比较多。因此,在内存与磁盘频繁交换数据的情况下,最好不用fprinf( )和fscanf( )函数,而用fread( )和fwrite( )。
12-2-6 随机文件的读写
1.文件位置指针的定位
在操作一个文件时,偶尔也需要对文件的某一部分或是一段进行读写操作。例如我们要截取一段视频或是一首歌,这时候在使用顺序的读写肯定是做不到的,为此C语言提供随机读写的功能,这样的话我就可以对文件任意位置进行读写了,首先我们要先来了解3个修改指针指向的函数,具体如下:
(1)rewind函数
函数调用的形式为:rewind(文件指针)
作用:该函数使文件的读/写位置指针重新指向文件的开头。
(2)fseek函数
函数调用的形式为:int fseek(文件指针,位移量,起始点)
作用:是将文件位置指针指向指定位置。
其中起始点的参数有三个,具体如下表12-2所示。
表12-2 fseek的参数的起始点
符号常数 |
数值码 |
含义 |
SEEK_SET: 文件开头 |
对应的数值是0 |
表示从文件开头进行偏移。 |
SEEK_CUR: 当前位置 |
对应的数值是1 |
表示于文件位置指针当前位置进行偏移。 |
SEEK_END: 文件结尾 |
对应数值是2 |
相对于文件末尾进行偏移。 |
例如 :fseek(fp,100L,0)或是fseek(fp,100L,SEEK_SET)都是表示,将位置指针移到离文件头100个字节处。
需要注意的是,fseek函数如果调用成功的话,返回值是1,如果有错误返回-1,此函数一般用于二进制文件,文本文件要进行字符转换,计算位置可能不准确。
(3)ftell函数的
函数调用的形式为: ftell(文件指针)
作用:该函数用于取得文件当前的读写位置。
在使用ftell()函数的时候,如果调用成功的话,返回文件位置指针的当前位置,如果读取错误时,函数的返回值为-1;
接下来我们通过一个案例来演示一下三个函数的使用。
实例12- 7 文件指针的定位。
#include <stdio.h>
int main() {
FILE * fp;
if((fp = fopen ("c:\\file.txt", "r"))!=NULL) {
fseek(fp,2,SEEK_SET);//指针文件开头移动2个位置
printf("指针移动了=%d \n",ftell(fp));//查看文件指针位置
rewind(fp);//文件指针回到原位
printf("指针移动了=%d \n",ftell(fp));
}else {
printf("文件读取失败");
}
getchar();
return 0;
}
运行结果,如我们代码注释的移动一样,如图12-11所示
图12- 11 实例12-7运行结果
2.对文件进行随机读写
通过对文件位置指针的讲解,接下来我利用上述的函数的相关的知识,来实现文件随机读写的操作。
实例12- 8 随机问价的读写。
#include <stdio.h>
int main() {
FILE *fp;
char buf[128];
char buffer[] = {"welikecprogram"};
if((fp = fopen ("c://test.txt","wb"))==NULL) {
printf("文件读取失败");
}
printf("把字符串welikecprogram写进文件里面\n");
fwrite (buffer, sizeof(char), 20, fp);
fclose (fp);
if ((fp = fopen("c://test.txt", "rb")) == NULL) {//打开源文件
printf("打开文件出错!\n");
}
fseek(fp,5, SEEK_SET);//文件操作指针偏移量为5个字节
printf("指针移动了=%d \n",ftell(fp));
fread(buf, sizeof(char), 20, fp);
printf("读取的数据内容是:%s \n", buf);
fclose(fp);
getchar();
return 0;
}
运行结果如图12-12所示,实现了文件的随机读取。
图12- 12 实例12-8运行结果
从图12-10中可以看出,控制台输出的内容是“ecprogram”,从代码中我们看出一开始我写入了welikecprogram,之后指针移动了5个距离,如图所示确实实现了文件的随机