fread / fwrite以大小和计数为参数的理由是什么?

时间:2008-11-17 16:09:07

标签: c libc

我们在这里讨论了为什么fread和fwrite为每个成员占用一个大小并计算并返回读/写成员的数量,而不仅仅是采用缓冲区和大小。我们可以想到的唯一用途是,如果你想读/写一个结构数组,这些结构不能被平台对齐整除,因此已被填充,但这并不能保证这一选择在设计中。

来自 FREAD(3)

  

函数fread()读取数据的nmemb元素,每个字符长度大小,   从流指向的流中,将它们存储在给定的位置   由ptr。

     

函数fwrite()写入数据的nmemb元素,每个字节大小   很长,到流指向的流,从该位置获取它们   由ptr。

提供      

fread()和fwrite()返回成功读取或写入的项目数   (即,不是字符数)。如果发生错误,或者   达到文件结束时,返回值是短项目计数(或零)。

7 个答案:

答案 0 :(得分:64)

fread(buf,1000,1,stream)和fread(buf,1,1000,stream)的区别在于,在第一种情况下,如果文件较小,则只获得一个1000字节或nuthin的块在第二种情况下,文件中的所有内容都会少于1000字节。

答案 1 :(得分:19)

它基于fread的实施方式。

单一UNIX规范说

  

对于每个对象,大小调用应为   制作到fgetc()函数和   按顺序读取存储的结果   完全是unsigned char的数组   覆盖对象。

fgetc也有这个说明:

  

因为fgetc()对字节进行操作,   读一个由...组成的字符   多个字节(或“多字节   字符“)可能需要多次调用   到fgetc()。

当然,这类似于UTF-8等花哨的可变字节字符编码。

SUS指出这实际上取自ISO C文件。

答案 2 :(得分:12)

这是纯粹的推测,但是在那些日子里(有些仍然存在)许多文件系统不是硬盘上的简单字节流。

许多文件系统都是基于记录的,因此为了有效地满足这些文件系统,你必须指定项目数(“记录”),允许fwrite / fread作为记录在存储上运行,而不仅仅是字节流。

答案 3 :(得分:9)

在这里,我来修复这些功能:

size_t fread_buf( void* ptr, size_t size, FILE* stream)
{
    return fread( ptr, 1, size, stream);
}


size_t fwrite_buf( void const* ptr, size_t size, FILE* stream)
{
    return fwrite( ptr, 1, size, stream);
}

至于fread() / fwrite()的参数的基本原理,我很久以前就失去了我的K& R副本,所以我只能猜测。我认为可能的答案是Kernighan和Ritchie可能只是认为执行二进制I / O最自然地会在对象数组上完成。此外,他们可能认为块I / O更快/更容易实现,或者在某些架构上更好。

尽管C标准指定fread()fwrite()fgetc()fputc()实现,但请记住标准在C定义后很久就存在了由K& R和标准中规定的东西可能不是原始设计师的想法。在K& R的“C编程语言”中所说的内容甚至可能与首次设计语言时的内容不同。

最后,这是P.J. Plauger在“标准C库”中对fread()所说的内容:

  

如果size(第二个)参数大于1,则无法确定   该函数是否还读取了超出其报告的size - 1个附加字符。   作为一项规则,您最好将该函数称为fread(buf, 1, size * n, stream);,而不是。{   fread(buf, size, n, stream);

基本上,他说fread()的界面已被破坏。对于fwrite()他指出,“写错误通常很少见,所以这不是一个主要的缺点” - 这是我不同意的陈述。

答案 4 :(得分:3)

可能它可以追溯到文件I / O的实现方式。 (在当天回来)在块中写入/读取文件然后一次写入所有内容可能会更快。

答案 5 :(得分:1)

我认为这是因为C缺少函数重载。如果有一些,大小将是多余的。但是在C中你无法确定数组元素的大小,你必须指定一个。

考虑一下:

int intArray[10];
fwrite(intArray, sizeof(int), 10, fd);

如果fwrite接受了字节数,您可以编写以下内容:

int intArray[10];
fwrite(intArray, sizeof(int)*10, fd);

但这只是效率低下。您将有sizeof(int)次系统调用。

应该考虑的另一点是,您通常不希望将数组元素的一部分写入文件。你想要整数或整数。 fwrite返回成功写入的多个元素。因此,如果您发现只写了2个低字节的元素,您会做什么?

在某些系统上(由于对齐),您无法在不创建副本和移位的情况下访问整数的一个字节。

答案 6 :(得分:1)

对大小和计数使用单独的参数可能对避免读取任何部分记录的实现有利。如果一个人使用管道之类的单字节读取,即使一个人使用的是固定格式的数据,则必须考虑到记录可能被两次读取分割的可能性。如果可以的话(例如)当有293个字节可用时,最多可对40个10字节的记录进行非阻塞读取,并让系统返回290字节(29条完整记录),同时为下一次读取留出3个字节的空间,这将更加方便。

我不知道fread的实现可以在多大程度上处理这种语义,但是对于可以承诺支持它们的实现,它们肯定很方便。