read,write属于Linux系统调用,fread,fwrite属于C语言标准库

使用系统调用会影响系统的性能。与函数调用相比,系统调用的开销要大些,因为在执行系统调用时,Linux必须从运行用户代码切换到执行内核代码,然后再返回用户代码。减少这种开销的一个好方法是,在程序中尽量减少系统调用的次数,并且让每次系统调用完成尽可能多的工作。例如,每次读写大量的数据而不是每次仅读写一个字符。
硬件会限制对底层系统调用一次所能读写的数据块大小。例如,磁带机通常一次能写的数据块长度是10k。所以,如果你试图写的数据量不是10k的整数倍,磁带机还是会以10k为单位卷绕磁带,从而在磁带上留下了空隙。

当对文件区域加锁之后(使用fcntl系统调用),你必须使用底层的read和write调用来访问文件中的数据,而不要使用更高级的fread和fwrite调用,这是因为fread和fwrite会对读写的数据进行缓存,所以执行一次fread调用来读取文件中的头100个字节可能(事实上,是几乎肯定如此)会读取超过100个字节的数据,并将多余的数据在函数库中进行缓存。如果程序再次使用fread来读取下100个字节的数据,它实际上将读取已缓冲在函数库中的数据,而不会引发一个底层的read调用来从文件中取出更多的数据。 为了说明这为什么是一个问题,让我们来考虑这样一个例子:两个程序都打算更新同一个文件。假设这个文件由200个全为零的字节组成。第一个程序先开始运行,并获得该文件头100个字节的写锁。它然后使用fread来读取这100个字节。但是正如我们在前面章节中所看到的,fread会一次读取多达BUFSIZE个字节的数据,因此,它实际上把整个文件都读到了内存中,但仅把头100个字节传递给程序。 接着,第二个程序开始运行。它获得了文件后100个字节的写锁。这个操作将会成功,因为第一个程序只锁定了文件的前100个字节。第二个程序将100~199字节的数据都写成2,关闭文件并解锁,最后退出程序。这时,第一个程序锁定了文件的后100个字节,然后调用fread来读取数据。尽管真正存在于文件中的数据是100个字节的2,但是因为先前数据已经被缓存,所以程序实际上读到的数据将是100个字节的零。但如果你使用read和write,这个问题就不会发生。
Logo

更多推荐