【问题标题】:fgetc vs getline or fgets - which is most flexiblefgetc vs getline 或 fgets - 最灵活
【发布时间】:2022-01-07 16:21:07
【问题描述】:

我正在从常规文件中读取数据,我想知道哪个可以提供最大的灵活性。

我发现 fgets 和 getline 都在一行中读取(一个具有最大字符数,另一个具有动态内存分配)。在 fgets 的情况下,如果行的长度大于给定的大小,则不会读取该行的其余部分,但仍会在流中缓冲。使用 getline,我担心它可能会尝试为一条非常长的线分配一大块内存。

对我来说显而易见的解决方案似乎是转向 fgetc,但这带来的问题是函数调用会很多,从而导致读取过程很慢。

在灵活性和效率之间的任何一种情况下,这种妥协是不可避免的,还是可以通过?

【问题讨论】:

  • 不用担心fgetc的函数调用开销。几乎可以肯定,瓶颈将是 IO,而不是函数调用开销。你可以使用getc,这是一个可以避免一些开销的宏......但是你根本不应该担心这个,直到/除非你有基准证明它实际上是一个问题。
  • 注意,无论你使用fgets还是fgetcread的实际数量都是一样的。这就是缓冲的全部目的。
  • 你有一个非常经典的权衡,这三个方面:(1) 能够处理任意长的行对你来说是多么重要,可能比你预先选择的任何固定大小都大? (2) 绝对、最大效率(不一定只是“足够快)”有多重要?(3) 你想做多少工作?根据你对这些问题的回答,你可以选择fgets,或者getline,或者你自己的涉及getc的输入循环,或者使用mmap的更奇特的东西。(我,我永远不会使用fgetc,尽管由于某种原因它现在似乎很流行。)
  • 感谢您的回复。能够处理长线并不重要,但绝对是首选。最大效率并不那么重要,所以我很可能会使用 getc 作为宏。

标签: c file-io fgets getline fgetc


【解决方案1】:

很大程度上取决于大小写。

getline()不是标准 C 库的一部分。它的功能可能不同 - 取决于实现和它遵循的其他标准 - 因此标准 fgetc()/fgets() 的优势。

...灵活性和效率之间不可避免的情况,...

OP 缺少更高的优先级。

  • 功能 - 如果代码无法与所选功能一起正常运行,为什么要使用它?示例:fgets() 和读取 空字符 会产生问题。

  • 清晰 - 不清晰,感受后来不得不维护代码的可怜灵魂的愤怒。


将允许最大的灵活性。 (?)

  • fgetc() 允许在低级别提供最大的灵活性 - 但是使用它来读取行的辅助函数往往会失败。

  • fgets() 在中级提供最大的灵活性 - 仍然必须处理长行和嵌入 空字符 的行,但至少避免了杂草中低水平的拖累。

  • getline() 在不需要高可移植性且不担心用户占用资源的风险时很有用。


为了可靠地处理用户/文件输入以读取一行,创建一个包装函数(例如int my_read_line(size_t buf, char *buf, FILE *f))并仅在用户代码中调用它。然后当出现问题时,可以在本地处理它们,而不管选择的低级输入函数。

【讨论】:

  • 用于机器人处理?避免使用直接使用标准函数并包装它?恐怕不行。
  • @LuisColorado 害怕robuts?嗯,这让人联想到一些有趣的searches。 IAC,一些标准函数,如fgets()strtol()malloc() invariable 需要一些辅助代码才能很好地使用它们。当该代码重复时,它又会调用辅助函数。
  • 不,我不担心鲁棒性,但我不确定将 api 包装成一组函数会产生更健壮的解决方案。如果保证函数不改变其界面,则更多。
【解决方案2】:

你提到的三个函数做不同的事情:

  • fgetc()FILE * 描述符中读取单个字符,它缓冲输入,因此,您可以以缓冲的方式处理文件,而无需为每个字符进行系统调用。当您的问题可以以面向角色的方式处理时,这是最好的。
  • fgets()FILE * 描述符中读取一行,这就像调用 fgetc() 来填充您传递给它的字符数组以便逐行读取。如果您的输入行长于您指定的缓冲区大小,则它具有进行部分读取的缺点。该函数还缓冲输入数据,因此非常高效。如果你知道你的行是有界的,那么最好逐行读取你的数据。有时您希望能够以无限行大小的方式处理数据,并且您必须重新设计您的问题以使用可用内存。那么下面的可能是更好的选举。
  • getline() 这个函数比较新,不是 ANSI-C,所以你可以将你的程序移植到一些缺少它的架构上。它是最灵活的,但代价是效率较低。它需要引用realloc()ated 的指针来填充越来越多的数据。它不会以可能填充系统上所有可用内存为代价来绑定行长度。缓冲区指针和缓冲区大小都通过引用传递以允许更新它们,因此您知道新字符串的位置和新大小。使用后必须是free()d。

之所以有三个而不是只有一个功能,是因为你对不同的情况有不同的需求,选择最有效的通常是最好的选择。

如果您打算只使用一个,您可能会遇到这样一种情况,即使用您选择的最灵活的功能不是最好的选择,您可能会失败。

【讨论】:

    猜你喜欢
    • 2023-01-21
    • 2011-07-08
    • 2021-12-28
    • 2016-03-31
    • 2015-05-28
    • 2019-04-23
    • 1970-01-01
    • 2019-09-22
    • 1970-01-01
    相关资源
    最近更新 更多