C

C 知识量:16 - 74 - 317

13.4 随机访问><

fseek()和ftell()函数- 13.4.1 -

fseek()函数和ftell()函数用于文件的随机访问。

1、fseek()函数有3个参数:

  • 第1个参数是FILE指针。指向待查找的文件。

  • 第2个参数是偏移量。表示从起点开始要移动的距离。它必须是一个long类型的值,可以为正(表示前移)、负(表示后移)或0(表示保持不动)。

  • 第3个参数是模式。它用于确定起始点。

对于第3个参数,在stdio.h中规定了几个表示模式的明示常量,其中,SEEK_SET代表文件开始处;SEEK_CUR代表当前位置;SEEK_END代表文件末尾。

以下是使用fseek()函数的示例:

fseek(fp, 0L, SEEK_SET);
fseek(fp, 2L, SEEK_CUR);
fseek(fp, -10L, SEEK_END);

如果运行正常,fseek()函数的返回值为0;如果出错,则返回-1。

2、ftell()函数通过返回距文件开始处的字节数来确定文件的位置,它的返回类型是long。例如:文件的第1个字节到文件开始处的距离是0,以此类推。ANSI C规定,该定义只适用于以二进制模式打开的文件,如果以文件模式打开则情况会不同。

以下是一个代码片段,功能是倒序打印文件。

fseek(fp, 0L, SEEK_END);
last = ftell(fp);
for (count = 1L; count <= last; count++) {
    fseek(fp, -count, SEEK_END); //后退
    ch = getc(fp);
}

以上代码的含义是:

  1. 把当前位置设置为距文件末尾0字节偏移量,即:把当前位置设置在文件结尾。

  2. 然后把文件开始处到文件结尾的字节数赋值给last。

  3. 最后使用循环打印文件内容。其中,第1轮迭代,先把程序定位到文件结尾的第1个字符,打印该字符。下一轮迭代把程序定位到前一个字符,并打印。重复此过程,直到打印完文件的第一个字符。

二进制模式和文本模式- 13.4.2 -

在二进制模式和文本模式下使用fseek()和ftell()函数存在一些差异。

1、UNIX只有一种文件格式,所以不需要进行特殊的处理。在MS-DOS环境下,许多编辑器都用Ctrl+Z标记文本文件的结尾。以文本模式打开这样的文件时,C能识别这个作为文件结尾标记的字符。但是,以二进制模式打开相同的文件时,Ctrl+Z字符被看作是文件中的一个字符,而实际的文件结尾符在该字符的后面。文件结尾符可能紧跟在Ctrl+Z字符后面,或者文件中可能用空字符填充,使该文件的大小是256的倍数。而且,在DOS环境下不会打印空字符。

2、MS-DOS用\r\n组合表示文本文件换行。以文本模式打开相同的文件时,C程序把\r\n“看成”\n。但是,以二进制模式打开该文件时,程序能看见这两个字符。通常,UNIX文本文件既没有Ctrl+Z,也没有\r,所以不需要进行特殊的处理。

ftell()函数在文本模式和二进制模式中的工作方式不同。ANSI C规定,对于文本模式,ftell()返回的值可以作为fseek()的第2个参数。而对于MS-DOS,ftell()返回的值把\r\n当作一个字节计数。

可移植性- 13.4.3 -

理论上,fseek()和ftell()应该符合UNIX模型。但是,不同系统存在着差异,有时确实无法做到与UNIX模型一致。因此,ANSI对这些函数降低了要求:

1、在二进制模式中,实现不必支持SEEK_END模式。移植性更高的方法是逐字节读取整个文件直到文件末尾。

2、在文本模式中,只有以下调用能保证其相应的行为:

函数调用 效果
fseek(file,0L,SEEK_SET) 定位至文件开始处
fseek(file,0L,SEEK_CUR) 保持当前位置不动
fseek(file,0L,SEEK_END) 定位至文件结尾
fseek(file,ftell-pos,SEEK_SET) 到距文件开始处ftell-pos的位置,ftell-pos是ftell()的返回值

fgetpos()和fsetpos()函数- 13.4.4 -

fseek()和ftell()函数都把文件大小限制在long类型能表示的范围内,随着存储设备的容量迅猛增长,文件也越来越大,long类型终将不能满足需要。为解决这个问题,ANSIC新增了两个处理较大文件的新定位函数:fgetpos()和fset-pos()。

fgetpos()和fset-pos()函数不使用long类型的值表示位置,它们使用一种新类型:fpos_t(代表file position type,文件定位类型)。fpos_t类型不是基本类型,它根据其他类型来定义。fpos_t类型的变量或数据对象可以在文件中指定一个位置,它不能是数组类型,除此之外,没有其他限制。实现可以提供一个满足特殊平台要求的类型,例如,fpos_t可以实现为结构。

fgetpos()函数的原型如下:

int fgetpos(FILE * restrict stream, fpos_t * restrict pos);

调用时,把fpos_t类型的值放在pos指向的位置上,该值描述了文件中的一个位置。如果成功,fgetpos()函数返回0;如果失败,返回非0。

fsetpos()函数的原型如下:

int fsetpos(FILE * stream, const fpos_t * pos);

调用时,使用pos指向位置上的fpos_t类型值来设置文件指针指向该值指定的位置。如果成功,fsetpos()函数返回0;如果失败,则返回非0。fpos_t类型的值应通过之前调用fgetpos()获得。