是否有getline
使用fread
(块 I/O)而不是fgetc
(字符 I/O)的函数?
通过 .逐字符读取文件会降低性能fgetc
。我们认为为了提高性能,我们可以fread
在getline
. 但是,这会引入超出行尾的潜在不良影响。至少,这将需要实现getline
来跟踪文件的“未读”部分,这需要超越 ANSI C FILE 语义的抽象。这不是我们想要自己实现的东西!
我们已经分析了我们的应用程序,性能缓慢与我们通过fgetc
. 相比之下,其余的开销实际上是微不足道的。我们总是从头到尾按顺序读取文件的每一行,并且我们可以在读取期间锁定整个文件。这可能使fread
-basedgetline
更容易实现。
那么,是否存在getline
使用fread
(块 I/O)而不是fgetc
(字符 I/O)的函数?我们很确定它确实如此,但如果不是,我们应该如何实现它?
更新找到了一篇有用的文章,在 C 中处理用户输入,作者是 Paul Hsieh。这是一种fgetc
基于 - 的方法,但它对替代方案进行了有趣的讨论(从有多糟糕开始gets
,然后讨论fgets
):
另一方面,C 程序员(甚至那些被认为有经验的程序员)的共同反驳是,应该使用fgets()作为替代方案。当然,fgets()本身并不能真正处理用户输入。除了有一个奇怪的字符串终止条件(遇到 \n 或 EOF,但不是 \0)之外,当缓冲区达到容量时选择终止的机制是简单地突然停止fgets()操作并 \0 终止它。所以如果用户输入超过了预分配缓冲区的长度,fgets()返回部分结果。处理这个程序员有几个选择;1) 简单地处理被截断的用户输入(当他们提供输入时,无法向用户反馈输入已被截断) 2) 模拟一个可增长的字符数组并通过对fgets()的连续调用来填充它. 第一个解决方案对于可变长度的用户输入几乎总是一个非常糟糕的解决方案,因为缓冲区在大多数情况下不可避免地会太大,因为它试图捕获太多的普通情况,而对于不寻常的情况来说太小了。第二种解决方案很好,只是正确实施可能很复杂。两者都没有处理fgets关于 '\0' 的奇怪行为。
留给读者的练习:为了确定调用fgets()实际读取了多少字节,可以尝试扫描,就像它所做的那样,扫描 '\n' 并跳过任何 '\0' 而不超过传递给fgets()的大小。解释为什么这对于流的最后一行是不够的。ftell()的哪些弱点阻止它完全解决这个问题?
留给读者的练习:通过在每次调用fgets()之间用非零值覆盖整个缓冲区来解决确定fgets()消耗的数据长度的问题。
因此,对于fgets(),我们只能选择编写大量代码并使用与 C 库的其余部分不一致的行终止条件,或者具有任意截止条件。如果这还不够好,那我们还剩下什么?scanf()以一种无法分离的方式将解析与读取混合在一起,并且fread()将读取字符串的末尾。简而言之,C 库让我们一无所有。我们被迫直接基于fgetc()滚动我们自己的。所以让我们试一试。
那么,是否存在getline
基于fgets
(并且不截断输入)的函数?