rewind、fseek、ftell为C库函数,有缓冲,lseek为系统函数,不带缓冲
理论
每个打开文件都有一个与其相关联的”当前文件偏移量“
它通常是一个非负整数。通常,读写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数当打开文件时通常其读写位置是指向文件开头, 若是以附加的方式打开文件(如O_APPEND), 则读写位置会指向文件尾. 当read()或* write()时, 读写位置会随之增加
我们可以去获取设置这个文件偏移量
lseek
lseek为系统函数,不带缓冲
#include
#include
/*
* 这是一个系统函数,不是库函数
* 功能:设置一个文件偏移量
*/
off_t lseek(int fildes, off_t offset, int whence);
__offset与__whence有关:
如果__whence是SEEK_SET,则该文件偏移量为距文件开始处offset个字节如果__whence是SEEK_CUR,则该文件偏移量为当前值+offset,offset可正可负
返回值:
如果lseek成功执行,则返回新的文件偏移量。如果文件描述符指向一个管道、FIFO或者网络套接字,则lseek返回-1, 并将errno设置为ESPIPE
ftell、fseek
/*
* 功能: 设置文件位置为给定流 stream 的文件的开头
* 参数: stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流
*/
void rewind(FILE *stream)
#include
/*
* 功能: 返回给定流 stream 的当前文件位置。
* 参数: stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
* 返回值:返回位置标识符的当前值。如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值。
*/
long int ftell(FILE *stream)
/*
* 功能: 重定位流(数据流/文件)上的文件内部位置指针
* 注意:文件指针指向文件/流。位置指针指向文件内部的字节位置,随着文件的读取会移动,文件指针如果不重新赋值将不会改变或指向别的文件。
* 参数:
* stream为文件指针
* offset为偏移量,正数表示正向偏移,负数表示负向偏移
* origin设定从文件的哪里开始偏移,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET
* SEEK_SET: 文件开头
* SEEK_CUR: 当前位置
* SEEK_END: 文件结尾
* 其中SEEK_SET,SEEK_CUR和SEEK_END依次为0,1和2.
* 反正: 成功,返回0,失败返回非0值,并设置error的值,可以用perror()函数输出错误
*/
int fseek( FILE *stream, long offset, int origin );
fgetpos、fsetpos
/*
* 作用: 获取流 stream 的当前文件位置,并把它写入到 pos。
* 参数:
* stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
* pos -- 这是指向 fpos_t 对象的指针
* 返回值: 如果成功,该函数返回零。如果发生错误,则返回非零值
*/
int fgetpos(FILE *stream, fpos_t *pos)
/*
* 作用: 设置给定流 stream 的文件位置为给定的位置
* 参数:
* stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
* pos -- 这是指向 fpos_t 对象的指针, 是由函数 fgetpos 给定的位置。
* 返回值: 如果成功,该函数返回零值,否则返回非零值,并设置全局变量 errno 为一个正值,该值可通过 perror 来解释。
*/
int fsetpos(FILE *stream, const fpos_t *pos)
这些都是C标准库中对文件定位相关的函数。
ftell与fseek一起使用,fsetpos与fgetpos一起使用。ftell与fseek返回的是长整数,而后面两个则是返回一个新类型(fpos_t)
ftell() 和 fseek() 用长整型表示文件内的偏移 (位置), 因此, 偏移量被 限制在 20 亿 (231-1) 以内。而新的 fgetpos() 和 fsetpos() 函数使用 了一个特殊的类型定义 fpos_t 来表示偏移量。这个类型会适当选择,
因此, fgetpos() 和 fsetpos 可以表示任意大小的文件偏移。fgetpos() 和 gsetpos() 也可以用来记录多字节流式文件的状态。
实践
lseek
1、测试标准输入被设置偏移量
#include
#include
#include
int main(void)
{
if (lseek(STDIN_FILENO, 0, SEEK_CUR) == -1)
printf("cannot seek\n");
else
printf("seek OK\n");
exit(0);
}
调用
$ ./apud < /etc/passwd
seek OK
$ cat < /etc/passwd | ./apud
cannot seek
注意:
某些设备可能会有负的偏移量,因此比较lseek的返回值要测试它是否等于-1
fgetpos、 fsetpos
#include
int main ()
{
FILE *fp;
fpos_t fpos;
fp = fopen("file.txt", "w+");
fgetpos(fp, &fpos);
fputc("Hello world\n", fp);
fsetpos(fp, &fpos);
fputs("这将覆盖之前的内容", fp);
fclose(fp);
return(0);
}
fseek、ftell
1、获取文件长度
UINT32 filesize(FILE *fp)
{
UINT32 fSet,fEnd,filelen;
fseek(fp,0,SEEK_SET);
fSet = ftell(fp);
fseek(fp,0,SEEK_END);
fEnd = ftell(fp);
rewind(fp);
return (filelen = fEnd - fSet);
}
rewind
#include
int main()
{
char str[] = "This is runoob.com";
FILE *fp;
int ch;
/* 首先让我们在文件中写入一些内容 */
fp = fopen( "file.txt" , "w+" ); /* 打开文件用于读写 */
fwrite(str , 1 , sizeof(str) , fp );
// fwrite(c, strlen(c) + 1, 1, fp);
fread(buffer, strlen(c) + 1, 1, fp);
printf("%s\n", buffer);
rewind(fp); //
printf("\n");
while(1)
{
ch = fgetc(fp);
if( feof(fp) )
{
break ;
}
printf("%c", ch);
}
fclose(fp);
return(0);
}