Skip to content

一个C文件IO问题

作为练习,我写了下面一个用FILE stream来做读写的C程序, 就是简单的读一个给定的文件,让后将每行打印出来,就像cat命令最简单的用法。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char * argv[]) {

        if (argc != 2) {
                printf("USAGE: %s FILE_NAME!\n",argv[0]);
                exit(EXIT_FAILURE);
        }

        int BUFFER_SIZE = 1024;
        char buf[BUFFER_SIZE];
        FILE *fp = fopen(argv[1],"r");
        if (fp == NULL) {
                printf("cannot open file: %s!",argv[1]);
                exit(EXIT_FAILURE);
        } else {
                while (!feof(fp)) {
                        fgets(buf,BUFFER_SIZE,fp);
                        printf("%s",buf);
                                        }
                                }
        fclose(fp);
}

然后编译:

gcc -o test test.c

运行:

./test tmp.txt
first line 
last line
last line

发现最后一行总是出现两次。怎么回事呢?

查了一下feof的手册才知道,当已经读到文件最后一行时,feof并不会马上返回一个非0值,或者说设置EOF标志,而是在下次调用feof时才设置EOF标志,然后再下次调用feof时才返回非零值,所以while循环总是会多跑一遍。

那么,在这个循环多跑的一遍中,buf字节数组中为什么还是最后一行的内容,而非空呢?

查了一下fgets的返回规则,原来当fgets碰到EOF时,它返回NULL指针,但是buf中的内容保持不变,也就是还保留着最后一次fgets的内容,也就是我们这个例子中的最后一行。这样我们就可以以fgets的返回值来判断是否结束循环。

更改后的程序如下:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char * argv[]) {
        int BUFFER_SIZE = 128;
        //int RT_CHAR = BUFFER_SIZE + 1;
        char buf[BUFFER_SIZE];
        if (argc != 2 ) {
                printf("Usage: %s FILE_NAME!\n",argv[0]);
                exit(EXIT_FAILURE);
        }
        FILE *fp = fopen(argv[1],"r");
        if ( fp != NULL ) {
               while (fgets(buf,BUFFER_SIZE,fp) != NULL ) {
                       printf("%s",buf);
               }
        } else {
                printf("Cannot open file: %s\n",argv[1]);
                exit(EXIT_FAILURE);
        }
        fclose(fp);
} //end of main()

另外要注意,用feof时,读文件出错也会异常结束,未必一定是文件读完了。

Avatar

专业Linux/Unix/Windows系统管理员,开源技术爱好者。对操作系统底层技术,TCP/IP协议栈以及信息系统安全有强烈兴趣。电脑技术之外,则喜欢书法,古典诗词,数码摄影和背包行。

Sidebar