以linux平台下的vim创建的文件为例,当读取指定文件中的内容时,文件的格式为:

内容+EOF 

其中 EOF为vim文件内容的结束标志。

每当用C语言读取文件内容时,文件指针要指向字符EOF之后才能判断文件已经结束。所以EOF内容会被读取,读取到的EOF通常会给我们带来困扰,如输出时会多输出一行。

为了解决多读取的EOF字符(在文件中不可见),我们用一个小小的逻辑算法来避免EOF字符带来的困惑,如打印读取的文件内容时不将读取到的EOF字符输出,或避免在读取到EOF字符(读取此字符不成功)后无判断文件是否结束的操作而又将上一次读取到的数据输出。

 

1.文件指针 文件内容

如data.in文件中的内容如下:

12345678

23456789

那么当用指针打开此文件并用相关的C语言文件操作函数来读取这个文件时,C语言文件指针执行过程(移位)如下:

  • 当打开文件时,文件指针指向文件中的第一个字符

        如FILE *fp = fopen("data.in", "r");要是打开data.in文件成功之后,文件指针fp就会指向文件中的第一个字符:'1'。

  • 每根据 要求(读一个字符,一行字符串等) 读取一次文件内容时,文件指针将指向下一个(临近)的字符。

        如data.in中的内容,此时用fgets(ar, 100, fp);语句后(读取文件中的一行字符串),文件指针将指向下一行的字符:'2'

  • 当文件指针指向EOF时,并不会认为文件内容已经结束。当指针指向EOF后一位时(把EOF读取后),此时文件内容才算结束。

如在data.in中,把字符'9'成功读取后,文件指针指向EOF字符。此时若判断文件是否结束,则不为结束;只有把EOF字符读取之后(文件指针指向EOF后时),再判断文件是否结束时,才会判断为结束。

 

2.正确使用feof()

#include <stdio.h>

#define SIZE            100
#define FILENAME        "data.in"

int main(void)
{
        int     ln;
        FILE    *fp;
        char    ar[SIZE];

        ln      = 0;

        if( (fp = fopen(FILENAME, "r") ) == NULL){
                        printf("Can not open file: %s\n", FILENAME);
                        return -1;
        }

        while( !feof(fp) ){
                fgets(ar, SIZE, fp);

                //If read EOF,
                //Do not record the line`s number,
                //Do not print the content to screen
                if( feof(fp) ){
                        break;
                }
                ln++;
                printf("%s", ar);
        }
        printf("The file`s line is %d\n", ln);
        fclose(fp);
        return 0;
}



这是一个打开与本源程序在同一个目录下叫data.in文件的程序。并读取data.in中的全部内容,并统计行数。

data.in中的内容如1中所述。

编译、运行此程序后的结果为:

12345678
23456789
The file`s line is 2

分析结果:

(1)此程序将data.in中可见内容照样输出(用fgets函数读取文件内容时,ar数组已经包含回车符,故不需要在printf打印语句中再添加回车),并正确统计了其内容行数。

(2)能正确将文件内容输出的关键语句是"if( feof(fp) ){break;}"需要将此语句加在"行数自增,打印行内容(ln++;printf("%s", ar))"语句之前。

 

3.非正确使用feof()

若将2中代码中的"if( feof(fp) ){break;}"语句去掉或者是写到"ln++;printf("%s", ar)"之后,则程序将不会得到预期效果。

a.将2中代码中的"if( feof(fp) ){break;}"语句去屏蔽,再编译运行程序得到结果:

12345678
23456789
23456789
The file`s line is 3
b.将将2中代码中的"if( feof(fp) ){break;}"语句写到"ln++;printf("%s", ar)"语句之后,再编译运行程序得到结果:

12345678
23456789
23456789
The file`s line is 3

分析结果:

造成a,b结果的原因在于:当读取EOF字符时,文件指针已经指向EOF之后,但此时没有进行读取文件内容是否结束的判断,从而没有进一步中断while循环,使fgets()函数读取EOF字符读取失败(不能讲字符EOF读入到数组ar中),从而ar数组里面的内容还是上一次读取的内容。所以当输出ar时,ar的值为上一次字符串值,并且ln++语句得以执行。故而是多输出文件中最后一行数据的结果!

 

总结:

在用非手动输入数据的程序手段进行数据的获取时(如读文件时,需要结合文件内容格式和相应函数功能(操作过程)来获取准确的数据)。有时候一字符只差,全程序皆输也!

 

Note Over。

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐