C: Reading a text file (with variable-length lines) line-by-line using fread()/fgets() instead of fgetc() (block I/O vs. character I/O)
是否有一个
通过
我们已经分析了我们的应用程序,并且性能下降的原因在于我们通过
那么,是否存在使用
更新找到了Paul Hsieh撰写的有用的文章,《用C处理用户输入》。这是基于
On the other hand the common retort from C programmers (even those considered experienced) is to say that fgets() should be used as an alternative. Of course, by itself, fgets() doesn't really handle user input per se. Besides having a bizarre string termination condition (upon encountering
or EOF, but not \0) the mechanism chosen for termination when the buffer has reached capacity is to simply abruptly halt the fgets() operation and \0 terminate it. So if user input exceeds the length of the preallocated buffer, fgets() returns a partial result. To deal with this programmers have a couple choices; 1) simply deal with truncated user input (there is no way to feed back to the user that the input has been truncated, while they are providing input) 2) Simulate a growable character array and fill it in with successive calls to fgets(). The first solution, is almost always a very poor solution for variable length user input because the buffer will inevitably be too large most of the time because its trying to capture too many ordinary cases, and too small for unusual cases. The second solution is fine except that it can be complicated to implement correctly. Neither deals with fgets' odd behavior with respect to '\0'.Exercise left to the reader: In order to determine how many bytes was really read by a call to fgets(), one might try by scanning, just as it does, for a '
' and skip over any '\0' while not exceeding the size passed to fgets(). Explain why this is insufficient for the very last line of a stream. What weakness of ftell() prevents it from addressing this problem completely?Exercise left to the reader: Solve the problem determining the length of the data consumed by fgets() by overwriting the entire buffer with a non-zero value between each call to fgets().
So with fgets() we are left with the choice of writing a lot of code and living with a line termination condition which is inconsistent with the rest of the C library, or having an arbitrary cut-off. If this is not good enough, then what are we left with? scanf() mixes parsing with reading in a way that cannot be separated, and fread() will read past the end of the string. In short, the C library leaves us with nothing. We are forced to roll our own based on top of fgetc() directly. So lets give it a shot.
那么,是否存在基于
不要使用
确定,请更新,因为这不是家庭作业:
-
memset 您的缓冲区到' 。
' -
使用
fgets 。 -
使用
memchr 查找第一个' 。
' -
如果未找到
' ,则该行比缓冲区长。扩大缓冲区,用
'' 填充新部分,然后将
'fgets 填充到新部分,必要时重复进行。 -
如果
' 之后的字符是
''\0' ,则fgets 由于到达行尾而终止。 -
否则,
fgets 由于到达EOF而终止,' 从您的
'memset 遗留下来,前一个字符是fgets 写入的终止空值,而在此之前的字符是读取的实际数据的最后一个字符。
如果您不关心支持带有嵌入式null的行,则可以消除
还有一种方法可以对
]"
fgets和fgetc / setvbuf之间没有太大的性能差异。
尝试:
1 2 3 4 5 6 7 8 9 10 11 |