11.5.3 fread_nolock_s(2)
这一段代码对streambufsize变量进行了赋值,如果文件自己有buffer,那么streambufsize就等于这个buffer的大小;如果文件没有使用buffer,那么fread_nolock_s就会使用一个内部的buffer,这个buffer的大小固定为_INTERNAL_BUFSIZ,即4096字节。接下来fread_nolock_s是一个循环:
while (count != 0) { read data decrease count } |
循环体内的操作用伪代码表示,大致的意思是:每一次循环都从文件中读取一部分数据,并且相应地减少count(还记得吗,count代表还没有读取的字节数)。当读取数据时,根据文件是否使用buffer及读取数据的多少分为3种情况,下面我们一一来看:
if (anybuf(stream) && stream->_cnt != 0) { nbytes = (count < stream->_cnt) count : stream->_cnt; memcpy_s(data, dataSize, stream->_ptr, nbytes); count -= nbytes; stream->_cnt -= nbytes; stream->_ptr += nbytes; data += nbytes; dataSize -= nbytes; } |
在if的判断句中,anybuf判断文件是否有缓冲,而stream->_cnt != 0判断缓冲是否为空。因此当且仅当文件有缓冲且不为空时,这段代码才会执行。
让我们一行一行地来看这段代码的作用。nbytes代表这次要从缓冲中读取多少字节。在这里,nbytes等于还须要读取的字节数(count)与缓冲剩余的字节数(stream->_cnt)中较小的一个。
接下来的一行使用memcpy_s将文件stream里_ptr所指向的缓冲内容复制到data指向的位置,如图11-13所示。
|
| (点击查看大图)图11-13 文件缓冲区操作 |
接下来的5行,皆是按照图11-13修正FILE结构和局部变量的各种数据。
memcpy_s是memcpy的安全版本,相对于原始的memcpy版本,memcpy_s接受一个额外的参数记录输出缓冲区的大小,以防止越界,其余的功能和memcpy相同。
以上代码处理了文件缓冲不为空的情况,而如果缓冲为空,那么又分为两种情况:
(1)需要读取的数据大于缓冲的尺寸。
(2)需要读取的数据不大于缓冲的尺寸。
对于情况(1),fread将试图一次性读取尽可能多的整数个缓冲的数据直接进入输出的数组中,如果缓冲尺寸为0,则直接将剩下的数据一次性读取。代码如下:
else if (count >= bufsize) { nbytes = ( bufsize (unsigned)(count - count % bufsize) : (unsigned)count ); nread = _read(_fileno(stream), data, nbytes); if (nread == 0) { stream->_flag |= _IOEOF; return (total - count) / size; } else if (nread == (unsigned)-1) { stream->_flag |= _IOERR; return (total - count) / size; } count -= nread; data += nread; }
|
在代码中,_read函数用于真正从文件读取数据。在这里我们先不管这个函数,在稍后的内容中会对此函数进行详细的介绍。如果要读取的数据不大于缓冲的尺寸,那么仅需要重新填充缓冲即可:
else { if ((c = _filbuf(stream)) == EOF) { return (total - count) / size; } *data++ = (char) c; --count; bufsize = stream->_bufsiz; } |
_filbuf函数负责填充缓冲。该函数的具体实现重要的部分只有一行:
stream->_cnt = _read(_fileno(stream), stream->_base, stream->_bufsiz);
|
可以看见所有的线索都指向了_read函数。_read函数主要负责两件事:
(1)从文件中读取数据。
(2)对文本模式打开的文件,转换回车符。
【责任编辑:
云霞 TEL:(010)68476606】