C语言:文件操作(2)
文件的顺序读写
关于对文件的读和写操作,一共有四组函数,我们先说写文件,再说读的文件的函数。
fputc和fgetc
fputc
fputc是输出单个字符到输出流中,使用包含两个参数,ch是要写入文件中的字符,stream是输出流。在"w"模式下使用。
比如说我们要写一个字符到text.txt文件中。
写入成功。
如果要把字符’a’到’z’都写入该文件中,我们可以这样写:
就写进去了。
fgetc
我们想从text.txt文件中读取单个字符出来,就可以用fgetc函数。该函数在"r"模式下使用。
fgetc是用来从输入流中读取单个字符的函数,包含一个参数stream,是读取字符的来源。该函数返回的是该字符的ascll值 ,为int类型。当遇到错误指示器或者读到文件末尾时,返回EOF。
我们从text.txt文件中读取一个字符:
当我们读取到一个字符时,文件指针pf就会自动指向下一个字符:
我们如果想把文件读完可以这样写:
当遇到文件末尾时返回EOF,循环停止。
fputs和fgets
fputs
fputs是用来输出一个字符串到输出流中的函数,包含两个参数,str是指向要写入的字符串的指针,stream是输出流。在"w"模式侠下是使用。我们想写"hello world"到文件date.txt中:
如果再写入一个字符串"wonderful"呢?
我们发现第二个字符串写入该文件时没有换行,直接在第一个字符串后面写入了。当我们想换行的时候,可以在第一个字符串后面手动添加\n:
这就是fputs的使用。
fgets
fgets就是从输入流中读取字符串的函数,包含三个参数:str,count,stream
。str就是用来放读取出来的字符串的字符数组的,count是读取出来字符的长度,因为会在读取出来的字符串后面主动添加’\0’,所以最多可以读取出count-1个字符,stream就是读取字符串来源的输入流。如果读到文件末尾或者遇到’\0’就自动停止读取。该函数在"r"模式下使用。
遇到换行符停止读取,所以只读了"hello world\n"。这时文件指针pf指向了字符’w’:
第二行字符串读取到文件末尾后停止读取。
fprintf和fscanf
fprintf
fprintf是输出格式化的数据到输出流中,在"w"模式下使用。可以对比printf的用法。
和printf相比,在前面多了一个参数stream输出流。
比如我们要写数据到文件date.txt中:
这样就可以写入数据到文件中了,结构体也可以写入:
fscanf
fscanf是从输入流中读取格式化的数据,在"r"模式下使用,使用也可以对照scanf。
与scanf相比前面多了个参数stream输入流。
比如说我们要从文件date.txt中读取格式化的数据:
fwrite和fread
fwrite
fwrite是写入格式化的数据到文件输出流,该函数在"wb"模式下使用。包含四个参数:buffer,指向要写入的数据的首对象。size,每个对象的大小,count,要写入的对象的个数。stream,文件输出流。
这样就可以把arr数组中的五个元素以二进制形式写进文件test.txt中了。
我们以记事本(文本文件的形式)打开该文件,是看不懂的。
但我们可以在程序中以二进制形式打开该文件:
这样就能看懂了,存了1,2,3,4,5这五个元素。
fread
fread是从文件输入流中读取数据块,该函数在"rb"模式下使用,包含参数跟fwrite一模一样,但参数意义变了,buffer是用来接收从文件中读取到的数据块的,size是数据块的大小,count是读取数据块的个数,stream是文件输入流。
比如我们要从文件test.txt中读取数据块:
读取成功。
文件的随机读写
当一个文件中存放abcdef时,我们想读完字符a后,下一个字符读b该怎么做?
我们知道,fgetc函数从文件中读取一个字符后,指向该文件的指针就会指向下一个字符。
当fgetc读完文件中的字符a时,指针pf就会偏移指向下一个字符b,如何跳过前面的字符读取到d?
fseek
介绍一个函数fseek,它是用来移动文件指针,改变下一次读取文件的位置的。包含三个参数,stream是打开的文件流,offset是偏移量,origin是基准位置,可以是三个参数:SEEK_SET,SEEK_CUR,SEEKEND。SEEK_SET是文件起始位置,SEEK_CUR是文件指针当前指向的位置,SEEK_END是文件末尾。offset这个偏移量就是相对于参数origin来说的。
比如说我读完字符a想直接读字符d,那我可以这样写:
通过fseek来偏移指针当前文件指针指向的位置,再通过fgetc读取文件指针指向字符的ascll值,就可以直接读取到字符d。
这里我们给origin传的是SEEK_CUR,是当前文件指针指向的位置。读取了字符a后当前文件指针指向的位置后移,指向了字符b,把文件指针往后偏移2个字节,该文件指针指向的就变成了字符d,通过fgetc读取到的字符就变成了d。
除了SEEK_CUR,我们还可以传另外两个参数,都可以达到同样的效果。
fseek(pf,3,SEEK_SET);//传的是文件起始位置,向后偏移3个字节,文件指针指向dfseek(pf,-2,SEEK_END);//传的是文件末尾,向前偏移两个字节,文件指针指向d这就是fseek函数的使用。
ftell
如果我们想知道目前文件指针相对于文件开头的偏移量,我们可以用ftell函数。传过去当前的文件指针sream,返回偏移量。注意返回值类型是long int。
读取字符d后,文件指针指向了字符e,相对于文件开头,a到e偏移了4个字节。
rewind
如果我们想让文件指针指向的位置回到文件开头,就可以使用rewind函数。
使用很简单,就把当前文件指针传入就行了。
使用rewind函数后,用ftell函数可以看出,当前文件指针相对于文件开头的偏移量为0,说明rewind函数成功地让文件指针指向的位置回到了文件开头。
文件读取结束的判定
在文件读取的时候,读取结束有两种可能:遇到错误指示器;读到文件末尾。我们不知道文件长度是多少,那如何判断文件是否读取结束呢?
fgetc,fgets,fread读取结束的判定
判断文件是否读取结束的办法是根据函数返回值来看的。
fgetc
fgetc在读取文件的时候,如果读取失败则会设置一个错误指示器,然后返回EOF(end of file)。如果读取到文件末尾也会返回EOF。所以判断fgetc返回值是不是EOF就可以判断文件读取是否结束。
fgets
fgets在读取文件的时候,如果读取失败则会设置一个错误指示器,然后返回NULL。如果读取到文件末尾也会返回NULL。所以判断fgetc返回值是不是EOF就可以判断文件读取是否结束。
fread
fread读取二进制文件返回的是读取成功的数据块的个数,比如我们要读取的文件中有8个数据块,第一次我读取了5个数据块,还剩3个数据块没读取。第二次我读取5个数据块,成功读取了3个数据块。当我们成功读取的数据块个数少于我们要读取的数据块的个数时,说明文件读取结束。
判断文件读取结束的原因
feof和ferror
feof是用来判断文件读取结束是不是因为读到文件末尾了,不是则返回NULL。
ferror是用来判断文件读取结束是不是因为遇到错误指示器了,不是则返回NULL。
比如说我们要判断一个文件读取结束的原因:
说明文件读取结束了,是读取到文件末尾才结束的。
文件缓冲区
ANSl C标准采用“缓冲文件系统”处理数据文件,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区,充满缓冲区后再从缓冲区逐个地将数据送到程序数据区,缓冲区的大小根据C编译系统决定。
