我需要阅读一行文本(以换行符结尾)而不对长度做出假设。所以我现在面临着可能性:
fgets
每次使用并检查最后一个字符是否为换行符并不断追加到缓冲区- 使用缓冲区读取每个字符
fgetc
,偶尔realloc
使用缓冲区
直觉告诉我这个fgetc
变体可能会更慢,但是我不知道fgets
如果不检查每个角色怎么能做到(而且我的直觉并不总是那么好)。线条很大,所以性能很重要。
我想知道每种方法的优缺点。先感谢您。
我建议fgets()
与动态内存分配结合使用 - 或者您可以研究getline()
POSIX 2008 标准中的接口,并且在更新的 Linux 机器上可用。这为您完成了内存分配工作。您需要密切关注缓冲区长度及其地址——因此您甚至可以自己创建一个结构来处理信息。
虽然fgetc()
也有效,但它稍微有点复杂 - 但只是稍微如此。在封面之下,它使用与fgets()
. 内部可能能够利用更快的操作 - 类似于strchr()
- 当您直接调用时不可用fgetc()
。
您的环境是否提供该getline(3)
功能?如果是这样,我会说去吧。
我看到的最大优势是它自己分配缓冲区(如果你愿意的话),如果realloc()
缓冲区太小,你会传入缓冲区。(所以这意味着你需要传入从 获得的东西malloc()
)。
这摆脱了 fgets/fgetc 的一些痛苦,您可以希望编写实现它的 C 库的人会注意提高它的效率。
奖励:Linux 上的手册页有一个很好的示例,说明如何以有效的方式使用它。
如果性能对您很重要,您通常希望调用getc
而不是fgetc
. 该标准试图使其更容易实现getc
为宏以避免函数调用开销。
除此之外,要处理的主要问题可能是您分配缓冲区的策略。大多数人使用固定增量(例如,当/如果我们用完空间时,再分配 128 个字节)。我建议改为使用 constant factor,因此如果空间不足,请分配一个缓冲区,例如,之前大小的 1 1/2 倍。
尤其是当作为宏实现时,和getc
之间的差异通常很小,所以你最好把注意力集中在其他问题上。getc
fgets
如果您可以设置最大行长度,即使是较大的行长度,也fgets
可以做到这一点。如果不是,多次fgets
调用仍然会比多次fgetc
调用更快,因为后者的开销会更大。
不过,一个更好的答案是,除非您必须这样做,否则不必担心性能差异。如果fgetc
足够快,那有什么关系?
如果您还没有读到行尾,我会分配一个大缓冲区,然后使用 fgets、检查、重新分配和重复。
每次阅读(通过 fgetc 或 fgets)时,您都在进行需要时间的系统调用,您希望尽量减少发生的次数,因此调用 fgets 的次数更少并且在内存中迭代更快。
如果您正在从文件中读取,则在文件中mmap()
ing 是另一种选择。