ftell、fread、fseek、feof 详细的使用介绍与注意细节

1. long ftell(FILE *stream);

功能:用于得到文件位置指针当前位置相对于文件首的偏移字节数

2. size_t fread ( void *buffer, size_t size, size_t count, FILE *stream)

功能:从一个文件流中读数据,最多读取count个元素,每个元素size字节,如果调用成功返回实际读取到的元素个数,如果不成功或读到文件末尾返回 0。

3. int fseek(FILE *stream, long offset, int origin)

功能:重定位文件内部位置指针

当offset是向文件尾方向偏移的时候(即为正值),无论加上偏移后是否超出文件尾,fseek都是返回0。
就算超出文件尾,用ftell得到的值仍是加上offset后的值,而不是文件末尾;
此时用fread会失败,返回0。

当offset是向文件头方向偏移的时候(即为负值),如果加上offset后没有超出文件头,是正常偏移,文件指针指向正确的偏移地址,fseek返回值为0;当offset超出文件头时,fseek返回出错-1值;
此时用ftell得到的仍是fseek之前的值,而不是0。

    iseek = fseek(pfRead, 1000, SEEK_CUR);  //0
    itell = ftell(pfRead);    //1000
    iread = fread(&ch, sizeof(char), 1, pfRead);    //0

    iseek = fseek(pfRead, -1001, SEEK_CUR);    //-1
    itell = ftell(pfRead);    //1000
    iread = fread(&ch, sizeof(char), 1, pfRead);    //0

4. int feof(FILE *stream)

功能:检测流上的文件结束符

feof与eof的区别
“C”语言的“feof()”函数和数据库中“eof()”函数的运作是完全不同的。数据库中“eof()”函数读取当前指针的位置,“C”语言的“feof()”函数返回的是最后一次“读操作的内容”。多年来把“位置和内容”相混,从而造成了对这一概念的似是而非。
那么,位置和内容到底有何不同呢?举个简单的例子,比如有人说“你走到火车的最后一节车箱”这就是位置。而如果说“请你一直向后走,摸到铁轨结束”这就是内容。也就是说用内容来判断会“多走一节”。这就是完全依赖于“while(!feof(FP)){…}”进行文件复制时,目标文档总会比源文档“多出一些”的原因。

在stdio.h中可以看到如下定义:

#define EOF (-1)
#define _IOEOF 0x0010
#define feof(_stream) ((_stream)->_flag & _IOEOF)
int c;
while(!feof(fp))
{
    c = fgetc(fp);
    printf("%X\n", c);
}

会发现多输出了一个FF,原因就是在读完最后一个字符后,fp->flag仍然没有被置为_IOEOF,因而feof()仍然没有探测到文件结尾。直到再次调用fgetc()执行读操作,feof()才能探测到文件结尾。这样就多输出了一个-1(即FF)。
正确的写法应该是:

int c;
c = fgetc(fp);
while(!feof(fp))
{
    printf("%X\n", c);
    c = fgetc(fp);//最后一个c的值为-1,但是无妨,因为其他所有的循环操作都要放在此句话上面
}

feof()可以用EOF代替吗?不可以。fgetc返回-1时,有两种情况:读到文件结尾或是读取错误。因此我们无法确信文件已经结束,
因为可能是读取错误! 这时我们需要feof()。

用fseek无论将文件位置指针设置成文件尾还是文件尾之后的值,feof都仍为0

    //文件长度为10
    iseek = fseek(pfRead, 10, SEEK_SET);    //0
    ieof = feof(pfRead);    //0

    iseek = fseek(pfRead, 11, SEEK_SET);    //0
    ieof = feof(pfRead);    //0


一些具体的易错点测试如下:

    unsigned char a;
    FILE *pfRead;

    if (fopen_s(&pfRead, "1.txt", "rb") != 0)   //该文件中共包含10个字符!
    {
        printf("can't open file\n");
        return -1;
    }

    int iseek, iread, itell, ieof;

    iseek = fseek(pfRead, 1000, SEEK_CUR);  //返回值为0,之后的注释都表示返回值
    itell = ftell(pfRead);    //1000
    iread = fread(&a, sizeof(char), 1, pfRead);    //0
    ieof = feof(pfRead);    //0

    iseek = fseek(pfRead, -1001, SEEK_CUR);    //-1
    itell = ftell(pfRead);    //1000
    ieof = feof(pfRead);    //0
    iread = fread(&a, sizeof(char), 1, pfRead);    //0


    iseek = fseek(pfRead, 0, SEEK_SET);    //0
    while (!feof(pfRead))    //最后一个数会多输出一次
    {
        iread = fread(&a, sizeof(char), 1, pfRead);    //前10次为1,最后一次为0
        printf("%c ", a);   
    }
    itell = ftell(pfRead);    //10

    //改成下面这样就不会多输出了
    iseek = fseek(pfRead, 0, SEEK_SET);
    iread = fread(&a, sizeof(char), 1, pfRead);    //1
    while (!feof(pfRead))   
    {
        printf("%c ", a);
        iread = fread(&a, sizeof(char), 1, pfRead);    //前9次为1,最后一次为0
    }
    itell = ftell(pfRead);    //10

    iseek = fseek(pfRead, 10, SEEK_SET);    //0
    ieof = feof(pfRead);    //0
    itell = ftell(pfRead);  //10
    iread = fread(&a, sizeof(char), 1, pfRead); //0
    ieof = feof(pfRead);    //16
    itell = ftell(pfRead);  //10

    iseek = fseek(pfRead, 11, SEEK_SET);    //0
    ieof = feof(pfRead);    //0
    iread = fread(&a, sizeof(char), 1, pfRead);    //0
    ieof = feof(pfRead);    //16

    system("pause");

你可能感兴趣的:(C/C++)