rewind
、fseek
、ftell
为C库函数,有缓冲,lseek
为系统函数,不带缓冲
每个打开文件都有一个与其相关联的”当前文件偏移量“
我们可以去获取设置这个文件偏移量
lseek()可以控制文件偏移量(文件的读写位置)
#include
#include
off_t lseek(int fildes, off_t offset, int whence);
功能:
参数:
SEEK_SET
表示文件开头,这样参数offset 即为新的读写位置.SEEK_CUR
表示当前位置SEEK_END
表示文件末尾__offset与__whence有关:
__whence
是SEEK_SET
,则该文件偏移量为文件头+offset
个字节,offset
可正可负__whence
是SEEK_CUR
,则该文件偏移量为当前值+offset
个字节,offset
可正可负__whence
是SEEK_END
,则该文件偏移量为文件尾+offset
个字节,offset
可正可负返回值:
lseek
成功执行,则返回新的文件偏移量。lseek
返回-1, 并将errno
设置为ESPIPE
错误:
我们来看个例子:下面例子测试标准输入被设置偏移量
#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
注意:
当需要在大于2G的文件中跳转或在更大的块设备中跳转的时候lseek
是无法完成任务的,这需要其他的文件跳转系统调用。
Linux内核驱动函数llseek
就可以完成这样的操作
#include
#include
int _llseek(unsigned int fd, unsigned long offset_high,unsigned long offset_low, loff_t *result,unsigned int whence);
而lseek64是_llseek的包装函数
#define _LARGEFILE64_SOURCE
/* See feature_test_macros(7) */
#include
#include
off64_t lseek64(int fd, off64_t offset, int whence);
注意
当对大于2G的文件或块设备文件操作时,open打开时flag上需要加上O_LARGEFILE 表示以大文件的方式打开。
添加O_LARGEFILE时编译时会出现错误
error: O_LARGEFILE undeclared (first use in this function)
解决的办法是添加宏
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* for O_DIRECT */
#endif
或者
#define __USE_FILE_OFFSET64
#define __USE_LARGEFILE64
#define _LARGEFILE64_SOURCE
注意宏添加在头文件前,不然依然报错
/*
* 功能: 设置文件位置为给定流 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 );
附加说明:fseek()不像lseek()会返回读写位置, 因此必须使用ftell()来取得目前读写的位置.
举个例子:
#include
main()
{
FILE * stream;
long offset;
fpos_t pos;
stream = fopen("/etc/passwd", "r");
fseek(stream, 5, SEEK_SET);
printf("offset = %d\n", ftell(stream));
rewind(stream);
fgetpos(stream, &pos);
printf("offset = %d\n", pos);
pos = 10;
fsetpos(stream, &pos);
printf("offset = %d\n", ftell(stream));
fclose(stream);
}
/*
* 作用: 获取流 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)
因此, fgetpos() 和 fsetpos 可以表示任意大小的文件偏移。fgetpos() 和 gsetpos() 也可以用来记录多字节流式文件的状态。
举个例子:
#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);
}
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);
}
#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);
}