我对C文件I/O有以下问题。
从物理层面(硬盘)来看,可以假设每次fread(n_blocks, size, length,FILE fp)
操作的成本应该是第一页(块)的一个随机访问和下一个相同缓冲区的n-1个顺序访问吗?
我做出这个假设是因为操作系统有那么多进程,很可能其中一个进程也在每个本地程序的fread
之间写入或读取文件,并且根据这个假设,硬盘会定位到另一个扇区/柱面。
这个假设正确吗?
length
)对应于某些离散的“访问操作”的数量。事实并非如此。 fread
所做的只是读取 size*length
个字节;因此,只要乘法不溢出,以下三个调用执行的是完全相同的操作:fread(n_blocks, size, length, fp);
fread(n_blocks, size*length, 1, fp);
fread(n_blocks, 1, size*length, fp);
fread/fwrite
会在您的进程的内存中读取和写入内部缓冲区。该缓冲区可以通过 setbuf/setvbuf
函数进行控制。当缓冲区已满/已空时,它们将把读/写操作转发到操作系统。操作系统有自己的文件缓存。如果您正在读取,而操作系统在缓存中找不到文件的某个部分,则程序将等待数据实际从驱动器获取。在写入时,数据将被复制到操作系统缓存中,并在操作系统决定将其写入驱动器之前一直驻留在那里,这可能会在您的程序关闭文件并退出很久以后才会发生。反过来,今天的硬盘具有自己的内部缓存,操作系统甚至可能意识不到。fread/fwrite
将执行多少次驱动器访问。只需知道 C 语言、操作系统和底层硬件将尽最大努力尽快提供所请求的数据即可。但是,请记住,整个堆栈都针对顺序访问进行了优化。因此,避免没有充分理由就跳转到文件中的其他位置。不是这样的。你甚至不能假设 fread
将触发物理 I/O。你的操作系统可以对 I/O 请求进行大量操作,包括缓存结果、重新排序和合并(或分割)读取(甚至有时写入)。
如果有大量的 I/O 操作正在进行,根据你(和可能的 I/O 流库)使用的缓冲区大小,你也不能指望获得顺序读取。一些操作系统提供了在文件描述符上“提示”你将按顺序读取(或 mmap 区域),这可能会有所帮助。