引言
在之前的学习中,我们了解了C语言指针和多级指针和“骚操作”:隐藏代码到数据区(函数指针)函数指针,在学习到后面需要提取程序的PE文件结构时,我发现必须要用到C语言的文件读写函数,在这里我们来介绍一下C语言的文件读写函数。
文件分类
在学习文件读写函数之前,我们先来了解一下文件类型:在C语言中,按照数据存储的编码形式,数据文件可以分为文本文件和二进制文件两种。
文本文件
文本文件是以ASCII码值进行存储与编码的文件,其文件的内容就是字符,存储的是ASCII码的二进制,也就是我们能够直观的看得懂的,比如:‘2’,‘34’,‘5’这样,文件的数据流为字符流。
二进制文件
二进制文件是存储二进制数据的文件,存储的是数据的补码,文件的数据流为二进制流。
文件读写函数
一.关于FILE
在学习文件读写函数之前,我们先来了解一下在我们使用所有文件读写函数时,定义的结构指针FILE:
FILE是C语言为了具体实现对文件的操作而定义的一个包含文件操作相关信息的结构类型,FILE *fp定义了一个结构指针,FILE类型是用typedef重命名的,在头文件stdio.h中定义,因此,使用文件读写函数时都需要#include<stdio.h>。
下面是FILE文件类型的说明:
typedef struct{ short level;//缓冲区使用量 unsigned flags;//文件状态描述 char fd;//文件描述符 shotr bsize;//缓冲区大小 unsigned char *buffer;//文件缓冲区的首地址 unsigned char *curp;//指向文件缓冲区的首地址 unsigned char hold;//其他信息 unsigned istemp; short token; }FILE;
1.打开文件和关闭文件
1.打开文件
打开文件功能用于建立系统与要操作的某个文件之间的关联,指定这个文件名并请求系统分配相应的文件缓冲区内存单元。打开文件由标准函数fopen()实现,其调用方式一般为:
fopen("文件名","打开方式");
这里我们给出函数原型:
FILE *open(char *name,char *mode);
函数原型中的name即文件名,mode为打开方式。在这里我们给出C语言所有的文件打开方式:
文件打开方式
使用方式 | 含义 | 使用方式 | 含义 |
“r" | 打开文本文件进行只读 | ”rb" | 打开二进制文件只读 |
“w” | 新建新文本文件进行只写 | “wb” | 建立二进制文件进行只写 |
“a" | 打开文本文件进行追加 | “ab" | 建立二进制文件进行写/追加 |
”r+" | 打开文本文件星星读/写 | “rb+” | 打开二进制文件进行读/写 |
“w+” | 建立新文本文件进行读/写 | “wb+” | 建立二进制文件进行读/写 |
“a+" | 打开文本文件进行读/写/追加 | ”ab+“ | 打开二进制文件进行读/写/追加 |
值得注意的是:fopen( )函数有返回值,如果文件成功打开或建立,则返回包含文件缓冲区等信息的FILE结构指针,如果未能成功打开或建立,则返回NULL(空值)的FILE指针。
为保证文件操作的可靠性,调用fopen( )函数时最好做一个判断,以确保正常打开后再进行读写。其形式为:
if((fp=fopen("abc.txt","r"))==NULL){ printf("File open error!\n"); exit(0); }
这里的exit(0)是系统标准函数,作用是关闭所有文件,并且终止程序的执行。参数0表示程序正常结束,非0参数通常表示不正常的程序结束。
这里还需要注意:文件一旦经fopen()正常打开,则对该文件的操作方式就被确定,并且直至文件关闭都不变,即若文件以r方式打开,则只能对该文件进行读操作,而不能进行写入数据操作。
一般进行文件读写操作时,常用到一下规则:
if 读文件 指定的文件必须存在,否则出错; if 写文件(指定的文件可以存在也可以不存在) if 以“w”方式写 if 文件已存在 源文件将被删去后重新建立; else 按指定的名字创建一个新文件; if 以“a”方式写 if 文件已存在 写入的数据将被添加到指定文件原有的数据后面,不会删去原有的内容; else 按指定的名字新建一个文件(与“w”相同); if 文件同时读和写 使用“r+”“w+”或“a+”打开文件;
2.关闭文件
当文件操作完成后,应及时关闭它以防止不正常的操作。
关闭文件通过调用标准函数fclose()实现,其一般格式为:
fclose(文件指针);
该函数将返回一个整数,若该数为0表示正常关闭文件,否则标志无法正常关闭文件,所以关闭文件时也应该使用条件判断:
if(fclose(fp){ printf("Can not close the file!\n"); exit(0); }
关闭文件操作除了强制把缓冲区的数据写入磁盘外,还将释放文件缓冲区单元和FILE结构指针,使文件指针与具体文件脱钩。
二.文件读写
1.字符方式读写函数fgetc()和fputc()
对于文本文件,存取的数据都是ASCII码字符文本,使用这两个函数读写文件时,逐个字符地进行文件读写。
(1).fgetc()
功能:实现从fp所指示的磁盘文件读入一个字符到ch。
函数调用格式:
ch=fgetc();
(2).fputc()
功能:把一个字符ch写到fp所指示的磁盘文件上。
函数调用格式:
futc(ch,fp);
返回值:若写文件成功,则返回ch,若写文件失败,则返回EOF。
2.字符串方式文件读写函数fputs( )和pgets( )
(1).fgets( )
功能:从文本文件中读取字符串。
函数调用格式:
fgets(s,n,fp);
其中s可以是字符数组名或者字符指针,n是指定读入的字符个数,fp时文件指针。
值得注意的是:函数被调用时,最多读取n-1个字符,当函数读取的字符达到指定个数,或接收到换行符,或接收到文件结束标志EOF时,将在读取的字符后面自动添加一个‘\0’字符。若有换行符,则将换行符保留(换行符在’\0’字符之前),若有EOF,则不保留EOF。
返回值:若成功读取,则返回读取的字符串,若读取失败,则返回空指针。
(2).fputs( )
功能:向指定的文本写入一个字符串。
函数调用格式:
fputs(s,fp);
其中s为要写入的字符串,可以是字符数组名,字符型指针变量或者是字符串常量,fp是文件指针。该函数把s写入文件时,字符串结束符’\0’不会被写入文件。
返回值:若成功写入,则返回所写的最后一个字符,若写入失败,则返回EOF。
3.格式化方式文件读写函数fscanf( )和fprintf( )
(1).fscanf( )
功能:从文件中按照给定的控制格式读取数据
函数调用格式:
fscanf(fp,格式字符串,输入表);
(2).fprintf( )
功能:按照给定的控制格式向文件中写入数据
函数调用格式:
fscanf(fp,格式字符串,输出表);
4.数据块方式文件读写函数fread( )和fwrite( )
这两个函数多用于读写二进制文件。
(1).fread( )
功能:可以用来读一组数据,如一个数组元素,一个结构变量的值等。二进制文件中的数据流是非字符的,它包含的是数据在计算机内部的二进制形式。
函数调用格式:
fread(buffer,size,count,fp);
其中buffer是一个指针,在函数fread( )中,他表示存放输入数据的首地址,size表示数据块的字节数,count表示要读写的数据块数。
如:fread(fa,4,5,fp);
表示从fp所指的文件中,每次读4个字节送入实数组fa中,连续读5次,即读5个实数到fa中。
返回值:成功读取到的次数
注意:size未读满时,算作读取失败
(2).fwrite( )
功能:可以用来写入一组数据,如一个数组元素,一个结构变量的值等。
函数调用格式:
fwrite(buffer,size,count,fp);
其中buffer表示存放输出数据的首地址,size表示数据块的字节数,count表示要读写的数据块数。
返回值:成功写入的次数
三.其他相关函数
1.文件定位函数
在文件读写的整个过程中,每一次成功的操作都将改变文件指针的位置,依次完成文件数据的访问与处理。
(1).重定位文件首函数rewind( )
功能:定位文件读写位置指针,使其指向读写文件的首地址,即打开文件时文件读写位置指针所指向的位置。
当访问某个文件,进行了文件读写,使指针指向了文件中间或末尾,又想回到文件的首地址重新进行读写时,可使用该函数,其调用格式为:
rewind(FILE *fp);
(2).指针移动控制函数fseek( )
功能:控制指针移动
函数调用格式:
fseek(fp,offset,form);
其中fp为文件指针,offset表示移动偏移量,它应该是long型数据,使用常量时,应加上后缀“L”,offset可为负值,form表示从哪个位置开始计算偏移量,位置可取三种:文件首部,当前位置和文件尾部,实际表示时分别对应值0、1、2,或常量SEEK_set,SEEK_CUR,SEEK_END。
(3).获取指针当前位置函数ftell( )
功能:获取当前文件读写位置,即相对于文件开头的偏移量(字节数)。
函数调用格式:
ftell(文件指针);
函数出错时返回-1L。
2.检测文件指针状态函数
(1).文件末尾检测函数feof( )
功能:判断fp指针是否已经到文件末尾,即读文件是否读到了文件结束的位置。
函数调用格式:
feof(fp);
返回值:成功返回1表示已经读到了文件末尾的位置,0表示文件未结束。
(2).读写错误检查函数ferror( )
功能:检查文件在用各种输入输出函数进行读写时是否出错。
函数调用格式:
ferror(fp);
返回值:若为出错,返回0,否则表示出错。
(3).出错标记清除函数clearerr( )
功能:清楚出错标志和文件结束标志,使他们为0值。
函数调用格式:
clearerr(fp);
文件指针必须是已经定义过的。
好了,有了这些知识,我们再加以练习,课程中的问题也就迎刃而解啦,相信大家学完后可以独立写出PE头部字段分析的程序啦,作业我会在之后上传到博客,期待大家的阅读。
关于C语言文件读写函数的介绍就到此为止,非常希望大家能够找出错误之处并提出宝贵意见,我将虚心接受!!!望我们共同进步!!!