文件经打开后,就可以对它进行读写操作了,文件读写的方式可分为顺序读写和随机读写。顺序读写指从文件第一个数据开始,按照数据在文件中的排列顺序逐个地读写;随机读写是指不按照数据在文件中的排列顺序,而是随机的对文件中数据进行读写。
用函数读取文件,只有当读取到文件结束字符后才能用此字符来判断文件内容是否已经结束。
1 常用文件顺序读写函数
(1)int fgetc( FILE *fp )
函数功能:从fp所指文件的当前位置读一字符,若读取成功则返回该字符,同时文件指针向后移动一个字符。或者返回EOF( END OF FILE ),EOF的值为-1。
参数含义:文件指针,fp指向某个文件。
返回:函数操作成功则返回读取的字符,若文件结束则返回EOF。
图1 fgetc函数功能验证程序
myfile.txt文件内容
图2 myfile.txt内容
执行结果:
程序执行结果
另外,fgetc在linux平台下操作方式为缓冲区文件系统操作方式。可将fgetc的参数换为标准输入流stdin,用键盘输入字符给fgetc来验证。
(2)int fputc( char ch, FILE*fp )
函数功能:将ch字符输出到fp所指的文件的当前位置上,若输出成功则返回ch,同时文件指针往后移一个位置;否则返回EOF。
参数含义:欲输出的文件流。
函数返回值:成功则返回输出的字符,否则返回EOF。
看起来好像很简单的样子,似乎木有啥子值得注意的。不过提一点最常见却一般木有引起俺们注意的问题,fputc将ch输出到fp指向的文件要在程序运行结束后才会将字符真正的送入到fp指向的文件中,缓冲区文件系统大概就是如此吧。谁说不是呢,咱们将字符或者字符串输出到stdin的时候,如果程序运行木有结束,咱是看不到输出结果的。这就是字符界面了。验证方法可以是写这样子一段程序,等程序运行结束之前就结束程序的运行[ linux下可按Ctrl + C 来终止当前程序的运行 ],然后跑到fp指向的文件中去看有木有字符ch。
(3)int fputs( char *str, FILE*fp )
函数功能:向fp所指向的文件的当前位置输出字符串str,同时文件指针向后移str长度个位置。
参数含义:str表示将要输入到fp所指文件的字符串,fp指向某个文件。
返回值:若将str成功输入到文件中则返回0,否则返回EOF。
对于此函数想要说的还是那句话,等程序运行结束后才能将str输入到fp指向的文件之中。
这看起来不大科学的样子,如果程序需要边写边读文件来不及等程序运行结束,可咋地办呢?
(4)char * fgets( char *str,int n, FILE *fp )
函数功能:从fp所指文件当前位置开始最多读入n – 1个字符,自动加上尾标记’\n’,作为字符串送到str中;如果在获取n – 1个字符之前遇到换行符或者结束符则输入提前结束,实际的字符数不到 n – 1个。
参数含义:str表示存储读取字符串的地址,n表示期望的当前次读取的最多的字符个数,fp为指向某个文件的文件指针。
返回值:若操作成功则返回str的地址,否则返回NULL。
写到这里,突然想到,从文件中读取数据,在缓冲文件系统下,也要程序运行结束才能将文件中的数据真正的传递给程序中的变量?一切都要在程序运行完毕之后才能出结果?那App的界面及数据刷新都是在死循环中实现的!还是输这只是linux字符界面?这个似乎不是简单的问题,这是一个具有数学性和哲学性的问题^-^,找不到验证的源头,要如何验证呢?程序木有结束时,输不出变量,倒是可以利用变量的值来操作一些其他的事情,如根据变量的值作为条件来建立一个文件夹等。事后查看是否有文件夹的存在。先就想想吧。
(5) int fprintf( FILE * fp,char format[], arg输出列表 )
函数功能:函数中的格式format和输出列表arg的形式和用法与printf中的使用方法一样[ fprintf就是根据此函数得来的,fp为stdin,printf不简单的用法呢,可以好好用用 ],只是这里是将数据输出到fp所指文件中。
参数含义:fp是指向某文件的文件指针,format输出的格式,跟arg参数对应,arg输出参数列表。
返回值:成功则返回输出个数;否则返回EOF。
格式说明可重新到网上刻意查看。
(6) int fscanf( FILE *fp,char *format, arg输入列表 )
函数功能:函数中的格式format和输入列表arg的形式和用法与scanf中的完全一样,fscanf还可以指定出stdin以外的其它文件流。
参数含义:fp为指向某文件的文件指针,format为读入的格式,arg为参数列表。
返回值:读入成功则返回读入的个数否则返回0.
格式说明可重新到网上刻意查看。
对于scanf和fscanf,还想要记录的是其特殊的读数据的方式:
(1)可规定读取输入流的长度。
(2)可在%后加*来跳过相应的数据长度。
(3)格式与参数列表的形式要对应。
(4)读取字符时,空格和转义字符都可读入。
(5)在读取数字时,遇到与格式输入规定格式不符合[字符,空格,回车,tab键,点,宽度结束时等,但这些字符依旧会留在缓冲区内 ]的数据就停止读取。
(7) int fread( char buf[],unsigned size, unsigned n, FILE *fp )
函数功能:从fp所指文件中,读取n段数据,每段数据长度为size(字符或者字节 ),读入的数据依次放入buf中。
参数含义:buf存读入数据的地址,size每段数据的大小,n读取数据段的段数,fp为指向某文件的文件指针。
返回值:若操作成功则返回实际读入的数据段个数,否则返回0。
(8) int fwrite( char buf[],unsignedsize, unsigned n, FILE *fp )
函数功能:将以buf为首地址的内存中,取每段为size[字符或者字节 ]大小的n段数据存入fp所指向的文件中。
返回值:成功则返回写入的数据段数,否则返回0。
在程序设计过程中,若往文件中写了数据,再向此文件中读数据时,一定要验证数据是否已经写入到了相应的文件之中。
fread和fwrite函数一般应用于二进制文件。
2 文件的随机读写
在C语言中,对文件的随机读写主要是指针文件位置指针,将文件位置指针定位在文件中的不同位置来实现文件的随机读写[ 非顺序读写 ]。
(1)int feof( FILE *fp )
函数功能:检测文件指针是否处于文件末尾。
参数含义:fp为指向某文件的文件指针。
返回值:若文件位置指针处于文件末尾则返回非0;否则返回0。
前面的程序用当前读取的字符是否为EOF来判断文件是否结束,这里直接提供了feof函数来判断文件内容是否结束。在利用feof函数时,要正确使用,否则有可能会多读取文件内容。
(2)int fseek( FILE *fp, longoffset, int base )
函数功能:将文件指针fp指向的文件的当前地址的文件指针按照base方式移动offset个单位。
参数含义:fp为指向某文件的文件指针,offset为文件位置指针的偏移量offset的符号表示文件位置指针的移动方向,为负表示前移[指针的前面],为正表示后移,可编写程序验证,来形成自己理解的前后移。base是表示是相对于文件的开头、相对于文件的当前位置还是文件末尾。base对应的宏值分别为SEEK_SEEK( 0 相对于文件开头 ), SEEK_CUR( 1 相对于文件的当前位置 ),SEEK_END(2相对于文件的末尾)。
返回值:移动成功则返回0,否则返回非0。
(3)long ftell( FILE *fp)
函数功能:取fp所指文件的当前位置。
返回值:成功则返回fp所指文件的当前位置,否则返回-1L。
3 文件操作的出错检测
(1)int ferror( FILE *fp )
函数功能:检查上次对fp所进行的操作是否成功。
返回值:若成功则返回0,否则返回非0.
参数含义:fp为指向某文件的函数指针。
(2)void clearen( FILE *fp )
参数含义:fp为指向需要操作的文件的文件指针。
函数功能:清除文件的错误标志和结束标志。文件操作产生错误时,其错误标志将一直保持,直到下一个输入输出操作或clearen函数的调用;文件结束标志也将保持到指针新的移动或clearen的调用。
这个函数主要针对ferror和feof函数的返回值,具体可写程序验证一番。
对于提到的这些关于文件操作的函数,只是供程序设计时文件操作块的一个索引。C库中不止这些文件操作函数,当需要实现这些功能时可以借助于以上提供的函数或者相关的函数。这也是提供了一个索引。
还有,在前几个函数中验证的函数的缓冲问题,说明了一点,这些C语言版本属于缓冲文件系统操作方式。
4 非缓冲文件系统
非缓冲文件系统是一种低级输入输出系统,相对来说程序的移植性较差。在非缓冲文件系统中,系统不会自动的分配缓冲区[缓冲文件系统就自动分配了呗就就是说 ],要由程序分配缓冲区给文件,且在非缓冲区中没有文件指针,而是通过一个称作“文件描述符”的整数来标识将要操作的文件。
在非缓冲文件系统中,同过非缓冲文件的操作函数来完成文件的操作过程。缓冲区文件系统与非缓冲区文件系统的文件操作函数的区别关键字为“缓冲区”。
(1)int create( char*filename, int mode)
函数功能:建立一个名为filename的文件,并以mode方式打开它。
参数含义:filename表示将要被建立文件的名字,mode规定为打开此文件的方式。Mode可取0[只读 ],1[ 只写 ],2[读/写 ]中的一个。
返回值:成功建立则返回该文件的描述符,否则返回-1.
通过文件建立或者打开,可以得到该文件的描述符,一旦一个文件描述符与某文件建立了联系就可以通过这个文件描述符访问该文件。
(2)int open( char *filename,int mode)
函数功能:以mode方式打开指定文件。
参数:filename表示欲打开的文件名,mode表示打开的方式。
返回值:成功则返回文件的描述符,否则返回-1.
(3)int close( int fd )
函数功能:关闭指定文件描述符fd对应的文件。
返回值:关闭成功则返回0,否则返回-1.
参数含义:fd为打开的文件描述符。
(4)int write( int fd, void*buf, unsigned int size )
函数功能:将缓冲区buf长度为size个字节的数据写到fd描述的文件中。
返回值:写入成功则返回写入的字节数,否则返回-1.
参数含义:fd某文件对应的文件描述符,buf欲将写入文件的数据,size是欲将写入文件数据的长度。
(5)int read( int fd, void *buf,unsigned int size)
函数功能:从fd所对应的文件中读取size个字节的数据存入buf中。
参数含义:fd为某打开文件的文件描述符,buf用来存储从文件中读取的数据,size是表示读取数据的长度。
返回值:操作成功则返回实际读出的字节数,否则返回-1.
(6)int lseek( int fd, longoffset, int base )
函数功能:对fd所指文件的位置指针,相对参数base指定的基准点,移动offset个字节。base的三种取值方式跟fseek一样。
返回值:成功则返回0,否则返回-1.
(7)int long tell( int fd)
取fd所指文件的当前位置;若成功则返回该位置,否则返回-1L。
数字带的后缀表明此数据的数据类型。
那么缓冲区与非缓冲区函数的区别是什么呢?我不知道,似乎没有操作过非缓冲区的操作系统或者是无意操作过了还不知道,我在整理文件操作函数时,发现了这么一个规律:缓冲区文件系统的操作函数喜欢以字符来作为操作单位,而非缓冲文件操作系统的函数喜欢用字节来做操作的基本单位。
Note Over。