fseek、ftell和rewind函数,C语言fseek、ftell和rewind函数详解

对于文件的读写方式,C 语言不仅支持简单地顺序读写方式,还支持随机读写(即只要求读写文件中某一指定的部分)。对顺序读写方式来说,随机读写方式需要将文件内部的位置指针移动到需要读写的位置再进行读写,这通常也被称为文件的定位

对于文件的定位,可以通过 rewind、fseek 与 ftell 函数来完成。

其中,rewind 函数用于将文件内部的位置指针重新指向一个流(数据流或者文件)的起始位置。这里需要注意的是,这里的“指针”表示的不是文件指针,而是文件内部的位置指针。即随着对文件的读写,文件的位置指针(指向当前读写字节)向后移动。而文件指针指向整个文件,如果不重新赋值,文件指针不会发生改变。

rewind 函数的一般原型如下所示:

void rewind(FILE *fp);

从上面的函数原型可以看出,rewind 并没有返回值,因此也无法做安全性检查。如下面的示例代码所示:
FILE *fp=NULL;
fp=fopen("Test.txt","r");
if(fp==NULL)
{
}
rewind(fp);
在上面的示例代码中,由于 rewind 函数没有返回值,所以我们很难判断“rewind(fp)”是否执行成功。因此,应该尽量使用 fseek 来替换 rewind 函数,从而以验证流已经成功地回绕。如下面的示例代码所示:
if (fseek(fp, 0L, SEEK_SET) != 0)
{
}
相对于 rewind 函数而言,fseek 函数的功能更加强大,它用来设定文件的当前读写位置,从而可以实现以任意顺序访问文件的不同位置,以实现文件的随机访问。其函数的一般原型如下所示:

int fseek(FILE *fp,long offset,int from);

如果该函数执行成功,fp 将指向以 from 为基准,偏移 offset 个字节的位置,函数的返回值为 0;如果该函数执行失败(比如 offset 超过文件自身大小),则不改变 fp 指向的位置,函数的返回值为 -1,并设置 errno 的值,可以用 perror 函数来输出错误信息。

对于 fseek 函数中的参数:第一个参数 fp 为文件指针;第二个参数 offset 为偏移量,它表示要移动的字节数,整数表示正向偏移,负数表示负向偏移;第三个参数 from 表示设定从文件的哪里开始偏移,取值范围如表 1 所示。

表 1 from参数取值表
起始点 表不符号 数字表示
文件首 SEEK_SET 0
当前位置 SEEK_CUR 1
文件末尾 SEEK_END 2

由表 1 可知:
  • SEEK_SET 表示从文件起始位置增加 offset 个偏移量为新的读写位置;
  • SEEK_CUR 表示从目前的读写位置增加 offset 个偏移量为新的读写位置;
  • SEEK_END 表示将读写位置指向文件尾后,再增加 offset 个偏移量为新的读写位置。

当 from 值为 SEEK_CUR 或 SEEK_END 时,参数 offset 允许出现负值。如下面的示例代码所示:
/*将读写位置移动到离文件开头100字节处*/
fseek(fp,100L,0);
/*将读写位置移动到离文件当前位置100字节处*/
fseek(fp,100L,1);
/*将读写位置退回到离文件结尾100字节处*/
fseek(fp,-100L,2);
/*将读写位置移动到文件的起始位置*/
fseek(fp,0L,SEEK_SET);
/*将读写位置移动到文件尾*/
fseek(fp,0L,SEEK_END);
不难发现,上面的语句“(void)fseek(fp,0L,SEEK_SET);”的作用实际上等同于 rewind 函数。与此同时,在使用 fseek 函数时,还应该注意如下 3 点。
  1. 首先,调用 fseek 函数的文件指针 fp 应该指向已经打开的文件,否则将会出现错误。
  2. 其次,fseek 函数一般用于二进制文件,当然也可以用于文本文件。需要特别注意的是,当 fseek 函数用于文本文件操作时,一定要注意回车换行的情况。因为在一般浏览工具(如 UltraEdit)中,回车换行被视为两个字符 0x0D 和 0x0A,但真实的文件读写和定位却按照一个字符 0x0A 进行处理。因此,在碰到此类问题时,可以考虑将文件整个读入内存,然后在内存中手工插入 0x0D的方法,这样可以达到较好的处理效果。
  3. 最后,fseek 函数只返回执行的结果是否成功,并不返回文件的读写位置。因此,你可以使用 ftell 函数来取得当前文件的读写位置。

ftell 函数的原型为:

long ftell(FILE *fp);

该函数用于得到文件位置指针当前位置相对于文件首的偏移字节数。在随机方式存取文件时,由于文件位置频繁前后移动,程序不容易确定文件的当前位置。在使用 fseek 函数后,再调用函数 ftell 就能非常容易地确定文件的当前位置。如下面的示例代码所示:
long getfilelength(FILE *fp)
{
    long curpos=0L;
    long length=0L;
    curpos = ftell(fp);
    fseek(fp, 0L, SEEK_END);
    length = ftell(fp);
    fseek(fp, curpos, SEEK_SET);
    return length;
}