105

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

fread(3)

函数 fread() 从 stream 指向的流中读取数据的 nmemb 元素,每个 size 字节长,并将它们存储在 ptr 给定的位置。

函数 fwrite() 将 nmemb 数据元素(每个 size 字节长)写入 stream 指向的流,从 ptr 给定的位置获取它们。

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

4

7 回答 7

79

fread(buf, 1000, 1, stream)and的不同之处fread(buf, 1, 1000, stream)在于,在第一种情况下,如果文件较小,您只会得到一个 1000 字节的块或什么都没有,而在第二种情况下,您会得到文件中小于和最多 1000 字节的所有内容。

于 2008-11-17T16:16:58.883 回答
23

它基于fread的实现方式。

单一 UNIX 规范说

对于每个对象,应对 fgetc() 函数进行大小调用,并将结果按照读取的顺序存储在恰好覆盖该对象的 unsigned char 数组中。

fgetc也有这个注释:

由于 fgetc() 对字节进行操作,因此读取由多个字节组成的字符(或“多字节字符”)可能需要多次调用 fgetc()。

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

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

于 2008-11-17T16:19:39.267 回答
15

这纯粹是猜测,但是在过去(有些仍然存在),许多文件系统并不是硬盘驱动器上的简单字节流。

许多文件系统是基于记录的,因此为了以有效的方式满足此类文件系统,您必须指定项目的数量(“记录”),从而允许 fwrite/fread 作为记录在存储上进行操作,而不仅仅是字节流。

于 2010-09-19T02:32:15.607 回答
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()的形式实现,但请记住,该标准在 K&R 定义 C 之后很久就已经存在,并且标准中指定的内容可能不在最初设计者的想法中。K&R 的“C 编程语言”中所说的内容甚至可能与最初设计该语言时不同。fgetc()fputc()

fread()最后,这是 PJ Plauger在“标准 C 库”中所说的:

如果size(第二个)参数大于 1,则您无法确定该函数是否还读取了size - 1超出其报告内容的其他字符。通常,您最好调用该函数fread(buf, 1, size * n, stream);而不是 fread(buf, size, n, stream);

基本上,他是说fread()的界面坏了。因为fwrite()他指出,“写错误通常很少见,所以这不是主要缺点”——我不同意这种说法。

于 2008-11-17T17:46:10.543 回答
3

很可能它可以追溯到文件 I/O 的实现方式。(回到过去)以块为单位写入/读取文件可能会更快,然后一次写入所有内容。

于 2008-11-17T16:21:29.933 回答
1

对于可以避免读取任何部分记录的实现,具有单独的大小和计数参数可能是有利的。如果要从管道之类的东西中使用单字节读取,即使使用的是固定格式的数据,也必须考虑到一条记录被拆分为两次读取的可能性。如果可以改为请求,例如,当有 293 个字节可用时,最多读取 40 个记录,每个记录 10 个字节,并让系统返回 290 个字节(29 个完整记录),同时保留 3 个字节为下一次读取做好准备,那将方便很多。

我不知道 fread 的实现在多大程度上可以处理这种语义,但它们肯定可以在承诺支持它们的实现上派上用场。

于 2018-08-11T01:34:03.443 回答
-2

我认为这是因为 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 个低字节,你会怎么做?

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

于 2012-04-18T11:20:58.387 回答