fread读取整个文件(fread函数返回值)
这篇文章给大家聊聊关于fread读取整个文件,以及fread函数返回值对应的知识点,希望对各位有所帮助,不要忘了收藏本站哦。
程序员的自我修养: fread-C语言是怎样读取文件的
为了效率的考虑,不至于频繁调用系统函数和访问IO设备,MSVC CRT的fread采用缓冲设计. C语言提供的关于缓冲的函数有:int flush(FILE* stream); int setvbuf(FILE* stream, char* buf, int mode, size_t size);/*缓冲模式mode有: 1.无缓冲模式 _IONBF 2.行缓冲模式 _IOLBF每收到一个换行符(/n或/r/n),就将缓冲flush掉 3.全缓冲模式 _IOFBF仅当缓冲满时才进行flush*/ void setbuf(FILE* stream, char* buf);等价于(void)setvbuf(stream, buf, _IOBBF, BUFSIZ); fread的调用过程大概是:fread-> fread_s(增加缓冲溢出保护,加锁)-> _fread_nolock_s(循环读取,缓冲)-> _read(换行符转换)-> ReadFile(读取文件)加注释的FILE结构如下:struct _iobuf{ char*_ptr; int _cnt;//剩余未读的字节数 char*_base;//文件的缓冲基址 int _flag;//打开文件的属性 int _file;//打开文件的编号 int _charbuf; int _bufsiz;//文件的缓冲的总的大小 char*_tmpfname;}; typedef struct _iobuf FILE;核心函数_fread_nolock_s(循环读取,缓冲)如下:size_t __cdecl _fread_nolock_s( void*buffer, size_t bufferSize, size_t elementSize, size_t num, FILE*stream){ char*data;/* point inside the destination buffer to where we need to copy the read chars*/当前放进字节的尾部 size_t dataSize;/* space left in the destionation buffer(in bytes)//buffer中剩余字节数*/ size_t total;/* total bytes to read//总共要读的字节数*/ size_t count;/* num bytes left to read//剩下要读的字节数*/ unsigned streambufsize;/* size of stream buffer*/ unsigned nbytes;/* how much to read now*/ unsigned nread;/* how much we did read*/ int c;/* a temp char*//* initialize local vars*/ data= buffer; dataSize= bufferSize; if(elementSize== 0|| num== 0){ return 0;}/* validation*/ _VALIDATE_RETURN((buffer!= NULL), EINVAL, 0); if(stream== NULL|| num>(SIZE_MAX/ elementSize)){ if(bufferSize!= SIZE_MAX){ memset(buffer, _BUFFER_FILL_PATTERN, bufferSize);} _VALIDATE_RETURN((stream!= NULL), EINVAL, 0); _VALIDATE_RETURN(num _bufsiz;} else{/* assume will get _INTERNAL_BUFSIZ buffer*/ streambufsize= _INTERNAL_BUFSIZ;}/* here is the main loop-- we go through here until we're done*/ while(count!= 0){/* if the buffer exists and has characters, copy them to user buffer*/ if(anybuf(stream)&& stream->_cnt!= 0){ if(stream->_cnt< 0){ _ASSERTE(("Inconsistent Stream Count. Flush between consecutive read and write", stream->_cnt>= 0)); stream->_flag|= _IOERR; return(total- count)/ elementSize;}/* how much do we want?(unsigned)count: stream->_cnt; if(nbytes> dataSize){ if(bufferSize!= SIZE_MAX){ memset(buffer, _BUFFER_FILL_PATTERN, bufferSize);} _VALIDATE_RETURN(("buffer too small", 0), ERANGE, 0)} memcpy_s(data, dataSize, stream->_ptr, nbytes);/* update stream and amt of data read*/ count-= nbytes; stream->_cnt-= nbytes; stream->_ptr+= nbytes; data+= nbytes; dataSize-= nbytes;} else if(count>= streambufsize){/* If we have more than streambufsize chars to read, get data by calling read with an integral number of bufsiz blocks. Note that if the stream is text mode, read will return less chars than we ordered.*/ if(streambufsize){/* In 64bit apps size_t is bigger than unsigned*(which is 32bit even in 64 bit machines), so* we need to split the read into INT_MAX chunks* since _read() only support up to _signed_ int*(even though the in parameter is unsigned).*/ if(count> INT_MAX){/* calc chars to read-- the largest multiple of streambufsize* smaller then INT_MAX*/ nbytes=(unsigned)(INT_MAX- INT_MAX% streambufsize);} else{/* calc chars to read--(count/streambufsize)* streambufsize*/ nbytes=(unsigned)(count- count% streambufsize);}} else{ nbytes=(count> INT_MAX)?(unsigned)INT_MAX:(unsigned)count;} if(nbytes> dataSize){ if(bufferSize!= SIZE_MAX){ memset(buffer, _BUFFER_FILL_PATTERN, bufferSize);} _VALIDATE_RETURN(("buffer too small", 0), ERANGE, 0)} nread= _read(_fileno(stream), data, nbytes); if(nread== 0){/* end of file-- out of here*/ stream->_flag|= _IOEOF; return(total- count)/ elementSize;} else if(nread==(unsigned)-1){/* error-- out of here*/ stream->_flag|= _IOERR; return(total- count)/ elementSize;}/* update count and data to reflect read*/ count-= nread; data+= nread; dataSize-= nread;} else{/* less than streambufsize chars to read, so call _filbuf to fill buffer*/ if((c= _filbuf(stream))== EOF){/* error or eof, stream flags set by _filbuf*/ return(total- count)/ elementSize;}/* _filbuf returned a char-- store it*/ if(dataSize== 0){ if(bufferSize!= SIZE_MAX){ memset(buffer, _BUFFER_FILL_PATTERN, bufferSize);} _VALIDATE_RETURN(("buffer too small", 0), ERANGE, 0)}*data++=(char) c;--count;--dataSize;/* update buffer size*/ streambufsize= stream->_bufsiz;}}/* we finished successfully, so just return num*/ return num;}其中,int __cdecl _filwbuf( FILE*str)#endif/* _UNICODE*/{ REG1 FILE*stream=NULL;/* In safecrt, we assume we always have a buffer*/ _VALIDATE_RETURN(str!= NULL, EINVAL, _TEOF);/* Init pointer to _iob2 entry.*/ stream= str; if(!inuse(stream)|| stream->_flag& _IOSTRG) return(_TEOF); if(stream->_flag& _IOWRT){ stream->_flag|= _IOERR; return(_TEOF);} stream->_flag|= _IOREAD;/* Get a buffer, if necessary.*/ if(!anybuf(stream)){#ifndef _SAFECRT_IMPL _getbuf(stream);#else/* _SAFECRT_IMPL*//* In safecrt, we assume we always have a buffer*/ _VALIDATE_RETURN(FALSE, EINVAL, _TEOF);#endif/* _SAFECRT_IMPL*/} else{ stream->_ptr= stream->_base;} stream->_cnt= _read(_fileno(stream), stream->_base, stream->_bufsiz);#ifndef _UNICODE if((stream->_cnt== 0)||(stream->_cnt==-1)){#else/* _UNICODE*/ if((stream->_cnt== 0)||(stream->_cnt== 1)|| stream->_cnt==-1){#endif/* _UNICODE*/ stream->_flag|= stream->_cnt? _IOERR: _IOEOF; stream->_cnt= 0; return(_TEOF);} if(!(stream->_flag&(_IOWRT|_IORW))&&((_osfile_safe(_fileno(stream))&(FTEXT|FEOFLAG))==(FTEXT|FEOFLAG))) stream->_flag|= _IOCTRLZ;/* Check for small _bufsiz(_SMALL_BUFSIZ). If it is small and if it is our buffer, then this must be the first _filbuf after an fseek on a read-access-only stream. Restore _bufsiz to its larger value(_INTERNAL_BUFSIZ) so that the next _filbuf call, if one is made, will fill the whole buffer.*/ if((stream->_bufsiz== _SMALL_BUFSIZ)&&(stream->_flag& _IOMYBUF)&&!(stream->_flag& _IOSETVBUF)){ stream->_bufsiz= _INTERNAL_BUFSIZ;}#ifndef _UNICODE stream->_cnt--; return(0xff&*stream->_ptr++);#else/* _UNICODE*/ stream->_cnt-= sizeof(wchar_t); return(0xffff&*((wchar_t*)(stream->_ptr))++);#endif/* _UNICODE*/}代码中分了三种情况:1)缓冲区不为空此时,把缓冲区中的数据复制到传入的字符数组中. 2)缓冲区为空,需要读取的数据大于缓冲的尺寸此时,直接调用函数_fread把文件中的内容写到传入的字符数组中. 3)缓冲区为空,需要读取的数据不大于缓冲的尺寸此时,调用函数_fread读满缓冲区,并再写缓冲区的一个字符到传入的字符数组中.若未读满传入的字符数组,循环执行上述1~3过程,直到读满或读到文件末尾(EOF).
c语言文件操作fwrite和fread
fread是C语言标准为中的一个函数。它从一个文件流中读数据,最多读取count个元素,每个元素size字节,如果调用成功返回实际读取到的元素个数,如果不成功或读到文件末尾返回 0。
fwrite是C语言标准库中的一个函数,指向文件写入一个数据块。示例如下:
//读取一个完整的文件
#include<stdio.h>
#include<stdlib.h>
intmain()
{
FILE*pFile;//文件指针
longlSize;//用于文件长度
char*buffer;//文件缓冲区指针
size_tresult;//返回值是读取的内容数量
pFile=fopen("myfile.bin","rb");
if(pFile==NULL){fputs("Fileerror",stderr);exit(1);}//如果文件错误,退出1
//获得文件大小
fseek(pFile,0,SEEK_END);//指针移到文件末位
lSize=ftell(pFile);//获得文件长度
rewind(pFile);//函数rewind()把文件指针移到由stream(流)指定的开始处,同时清除和流相关的错误和EOF标记
//为整个文件分配内存缓冲区
buffer=(char*)malloc(sizeof(char)*lSize);//分配缓冲区,按前面的lSize
if(buffer==NULL){fputs("Memoryerror",stderr);exit(2);}//内存分配错误,退出2
//该文件复制到缓冲区
result=fread(buffer,1,lSize,pFile);//返回值是读取的内容数量
if(result!=lSize){fputs("Readingerror",stderr);exit(3);}//返回值如果不和文件大小,读错误
//terminate//文件终止
fclose(pFile);
free(buffer);
return0;
}综合使用的例子。
#include<stdio.h>
intmain()
{
FILE*pFile;
floatbuffer[]={2.0,3.0,8.0};
pFile=fopen("myfile.bin","wb");//打开文件写操作
fwrite(buffer,1,sizeof(buffer),pFile);//把浮点数组写到文件myfile.bin
fclose(pFile);//关闭文件
floatread[3];
pFile=fopen("myfile.bin","rb");//重新打开文件读操作
fread(read,1,sizeof(read),pFile);//从文件中读数据
printf("%f\t%f\t%f
",read[0],read[1],read[2]);
fclose(pFile);//关闭文件
return0;
}
C语言中fread的一些疑问
L_o_o_n_i_e回答得不怎么准确!
我帮你解释下:
首先介绍fread函数
功能:从一个流中读数据
函数原型: int fread(void*ptr, int size, int nitems, FILE*stream);参数:用于接收数据的地址(指针)(ptr)
单个元素的大小(size):单位是字节而不是位,例如读取一个整数值就是4元素个数(nitems)
提供数据的文件指针(stream)
返回值:成功读取的元素个数
由上面介绍知道fread函数的第一个参数是个指针变量,可以指向任意类型实参!
严归正传,对于你这里的问题,你代码中的s是个结构体数组变量,跟普通数组变量一样,数组名本身就是个指针常量,所以在buffer位置写成s是没有问题的。
那么为什么你这里读会变乱码呢?
虽然你帖的代码并没有全,但从你说的读取是乱码,我大概猜到在你用fwrite函数把数据写进文件的时候是以每次一个结构体大小(也就是仅仅是数组s的一个元素而已,也就对应一个下标而已)和一个数据块的方式写进文件里的。所以当你用fread函数读取的时候,假设你在buffer位置写成s,本身语法是没有问题的,但是就相当于你把数组s的仅一个元素的数据大小当成所有s的数据存到s中,也就是没有对应起来,所以显示会是乱码。
所以你可以有两种方式实现:
方式一:
在写的时候按一次以s的一个元素的数据大小作为一个数据块依次写进文件,然后读取时候也以同样方式读出来。
代码可以这么写:
假设s的大小为:SIZE_S
for(count= 0; count< SIZE_S; count++)
fwrite(&s[count], sizeof(struct student), 1, fp);
然后读取时:
for(count= 0; count< SIZE_S; count++)
fread(&s[count], sizeof(struct student), 1, fp);
方式二:
以整个数组s的数据大小作为一个数据块一次写进文件,然后读取时也同样全部读出来,最后可以以循环的方式打印出来。
代码实现如下:
假设s的大小为:SIZE_S
fwrite(s, SIZE_S* sizeof(struct student), 1, fp);
然后读取时:
fread(s, SIZE_S* sizeof(struct student), 1, fp);
最后打印:
for(count= 0; count< SIZE_S; count++)
fread(&s[count], sizeof(struct student), 1, fp);
明白了记得给哥哥顶下~~~ ^_^
fread读取整个文件的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于fread函数返回值、fread读取整个文件的信息别忘了在本站进行查找哦。