C读线的fgets与fgetc

C读线的fgets与fgetc,c,io,stdio,fgets,fgetc,C,Io,Stdio,Fgets,Fgetc,我需要阅读一行文字(以换行符结尾),而不必假设长度。因此,我现在面对各种可能性: 使用fgets,每次检查最后一个字符是否为换行符并连续追加到缓冲区 使用fgetc和偶尔使用realloc缓冲区读取每个字符 直觉告诉我,fgetc变体可能会慢一些,但我不明白fgets如何在不检查每个字符的情况下完成它(而且我的直觉并不总是那么好)。线路相当大,因此性能非常重要 我想知道每种方法的利弊。提前谢谢。如果您可以设置最大行长度,即使是较大的行长度,那么一个fgets就可以了。否则,多个fgets调用

我需要阅读一行文字(以换行符结尾),而不必假设长度。因此,我现在面对各种可能性:

  • 使用
    fgets
    ,每次检查最后一个字符是否为换行符并连续追加到缓冲区
  • 使用
    fgetc
    和偶尔使用
    realloc
    缓冲区读取每个字符
直觉告诉我,
fgetc
变体可能会慢一些,但我不明白
fgets
如何在不检查每个字符的情况下完成它(而且我的直觉并不总是那么好)。线路相当大,因此性能非常重要


我想知道每种方法的利弊。提前谢谢。

如果您可以设置最大行长度,即使是较大的行长度,那么一个
fgets
就可以了。否则,多个
fgets
调用仍将比多个
fgetc
调用更快,因为后者的开销更大


不过,更好的答案是,除非您不得不这样做,否则不值得担心性能差异。如果
fgetc
足够快,那又有什么关系呢?

您的环境是否提供了
getline(3)
功能?如果是这样的话,我会说去做

我看到的最大优势是它自己分配缓冲区(如果您愿意),如果缓冲区太小,它将
realloc()
您传入的缓冲区。(这意味着您需要传入从
malloc()
获取的内容)

这消除了fgets/fgetc带来的一些痛苦,您可以希望编写实现它的C库的人会注意提高它的效率


额外好处:Linux上的手册页提供了一个很好的示例,说明了如何高效地使用它。

我建议使用
fgets()
结合动态内存分配-或者您可以研究POSIX 2008标准中的接口,该接口可在更新的Linux机器上使用。这会为您分配内存。您需要对缓冲区长度及其地址进行标记,这样您甚至可以自己创建一个结构来处理信息


虽然
fgetc()
也能工作,但它稍微有点烦躁——但只是稍微有点烦躁。在盖子下面,它使用与
fgets()
相同的机制。内部可能能够利用更快的操作(类似于
strchr()
),这在您直接调用
fgetc()
时是不可用的。

我会分配一个大的缓冲区,然后使用fgets,检查、重新定位和重复(如果您没有读到行的末尾)

每次读取(通过fgetc或fgets)时,您都在进行需要时间的系统调用,您希望将发生的次数减至最少,因此调用fgets的次数更少,在内存中进行迭代的速度更快


如果您正在从文件中读取,则文件中的
mmap()
ing是另一个选项。

如果性能对您很重要,您通常希望调用
getc
,而不是
fgetc
。该标准试图使
getc
作为宏更容易实现,以避免函数调用开销

除此之外,要处理的主要问题可能是分配缓冲区的策略。大多数人使用固定增量(例如,当/如果空间用完时,再分配128字节)。我建议改为使用常数因子,因此如果空间不足,请分配一个缓冲区,比如说,是以前大小的1 1/2倍


特别是当
getc
作为一个宏实现时,
getc
fgets
之间的差异通常非常小,因此最好集中精力解决其他问题。

不幸的是(很抱歉,我在问题中没有提到这一点)我需要使用标准的东西:-(getline函数听起来确实很吸引人。嗯,它是标准的(对于一些标准的定义)。参见,又称“IEEE Std 1003.1”™-2008“又名“POSIX C 2008”。但很不幸,标准!=广泛存在。我感觉到了你的痛苦。getline很性感:-)
getline()
功能很好;名称
getline()
是对用户名称空间的严重入侵,抢占了一个更广泛使用的函数名(例如,请参见K&R 1和2)具有多种多样的接口。使用该名称是一个令人震惊的决定;提供该功能是一个极好的决定。唯一令人惊讶的是没有处理CRLF行结尾的功能;相关的
getdelim()
函数可以处理CR或LF或NUL行结尾,但不能处理CRLF行结尾。我不得不在系统调用部分反驳你:stdio库进行缓冲,所以我不认为每个函数调用都会转换为系统调用。我可能错了,这是真的,但对于fgets,他将拥有更细粒度的控制。如果他有一些id他可以优化缓冲区长度,而不是fgetc,fgetc将进行缓冲,但完全不知道理想的缓冲区长度。当使用
fgets
实现
getline
函数时,一个限制是不可能处理空字节和不以换行字符结尾的文件r。如果
fgets
遇到EOF条件并返回时没有换行符,则只能假设字符串以第一个空字节结尾。(在其他情况下,您可以执行
strchr(buf,'\n')
以查找停止读取的位置,或者如果没有
'\n'
,则需要
realloc
)如果文件包含空字节,则它不是文本文件。(它可能是宽字符文件,但需要使用宽字符I/O函数来读取它。)和
fgets()
不是为处理包含空字节的文件而设计的,这正是因为它没有给出读取多少字节的可靠指示。如果数据文件包含空字节,