[英]Reading from file and exiting loop using feof()
该链接说明了为什么feof()
不好用作循环的退出指示器。
不安全==>在while中有feof()
检查,而while中有fgets()
。
安全==>让while本身的fgets()!=NULL
检查。
我应该看到不安全的代码会执行额外的while循环迭代,但是两者都执行相同(且正确)的循环次数。 有人可以帮我了解这里发生了什么吗?
编辑:链接实际上确实说明了为什么会发生这种情况,但是下面的正确答案使我能够准确地了解自己正在阅读的内容。 我的文件的最后一行没有'\\ n',因此得到了相同的结果。
这是文件内容:
abcd
efgh
ijkl
这是代码:
void testUnsafe(void) {
FILE *f;
char buf[20];
f = fopen("fil.txt", "r");
while (!feof(f)) {
fgets(buf, 20, f);
if (buf[strlen(buf) - 1] == '\n') //cleaner
buf[strlen(buf) - 1] = '\0';
printf("%s , %d\n", buf, strlen(buf));
}
fclose(f);
}
void testSafe(void) {
FILE *f;
char buf[20];
f = fopen("fil.txt", "r");
while (fgets(buf, 20, f) != NULL) {
if (buf[strlen(buf) - 1] == '\n') //cleaner
buf[strlen(buf) - 1] = '\0';
printf("%s , %d\n", buf, strlen(buf));
}
fclose(f);
}
输出为:
******unsafe test********
abcd , 4
efgh , 4
ijkl , 4
********safe test********
abcd , 4
efgh , 4
ijkl , 4
如果您的文本文件在文本的最后一行之后没有换行符结束,则testUnsafe()
函数将在读取最后一行时到达文件结尾,并产生您显示的三行输出。
如果文本文件的最后一行之后确实有换行符,则该函数将读取最后一行,包括换行符, 而不会到达文件末尾。 当它再次进入while()
循环时,它将读取零个字符,设置文件结束标志,并从最后一轮输出仍在缓冲区中的最后一行。
while (!feof(f))
构造本身并不是不安全的 。 忽略检查不安全的fgets()
的返回值。
我尝试了两个示例,但结果却不同。 函数testUnsafe()
将文件的最后一行打印了两次。 有两个原因。
如果读取操作试图读取文件末尾,则feof()
函数将返回非零值。
函数testUnsafe()
不检查fgets()
的返回值,因此在达到feof()
条件之前重复先前读取的字符串。
我将您的函数复制到了我的测试程序中
#include <stdio.h>
#include <string.h>
void testUnsafe(void) {
FILE *f;
char buf[20];
f = fopen("fil.txt", "r");
while (!feof(f)) {
fgets(buf, 20, f);
if (buf[strlen(buf) - 1] == '\n') //cleaner
buf[strlen(buf) - 1] = '\0';
printf("%s , %d\n", buf, strlen(buf));
}
fclose(f);
}
void testSafe(void) {
FILE *f;
char buf[20];
f = fopen("fil.txt", "r");
while (fgets(buf, 20, f) != NULL) {
if (buf[strlen(buf) - 1] == '\n') //cleaner
buf[strlen(buf) - 1] = '\0';
printf("%s , %d\n", buf, strlen(buf));
}
fclose(f);
}
int main()
{
testUnsafe();
printf ("\n\n");
testSafe();
return 0;
}
测试文件:
Line 1
Line 2
Line 3
testUnsafe()
输出:
Line 1 , 6
Line 2 , 6
Line 3 , 6
Line 3 , 6
testSafe()
输出:
Line 1 , 6
Line 2 , 6
Line 3 , 6
基本上,要阅读所有行,您必须使用类似的算法。 如果ou在文件末尾没有换行符,则一定要加载所有行。
唯一的例外是最后一行不确定结尾处是否有LF。
除了检查缓冲区溢出之类的东西以优化内存使用外,还可以在将其添加到数组之前调用realloc()修剪缓冲区。
buffer = (char*)malloc(bufferSize);
while(fgets(buffer, bufferSize, file) != NULL) {
//here store your pointer in array...
buffer = (char*)malloc(bufferSize);
};
free(buffer);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.