Linux C/C++编程:lseek、fseek、ftell、rewind、fgetpos、fsetpos、
rewind、fseek、ftell为C库函数,lseek为系统函数/** 功能: 设置文件位置为给定流 stream 的文件的开头* 参数: stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流*/void rewind(FILE *stream)#include <stdio.h>/** 功能: 返回给定流 stream 的当前文件位置。* 参数:stre
rewind
、fseek
、ftell
为C库函数,有缓冲,lseek
为系统函数,不带缓冲
理论
每个打开文件都有一个与其相关联的”当前文件偏移量“
- 它通常是一个非负整数。
- 通常,读写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数
- 当打开文件时通常其读写位置是指向文件开头, 若是以附加的方式打开文件(如O_APPEND), 则读写位置会指向文件尾. 当read()或* write()时, 读写位置会随之增加
我们可以去获取设置这个文件偏移量
lseek
lseek()可以控制文件偏移量(文件的读写位置)
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fildes, off_t offset, int whence);
功能:
- 设置一个文件偏移量
- lseek为系统函数,不带缓冲
参数:
- fildes 为已打开的文件描述词
- 参数 whence 为下列其中一种:
SEEK_SET
表示文件开头,这样参数offset 即为新的读写位置.SEEK_CUR
表示当前位置SEEK_END
表示文件末尾
- offset 为根据参数whence来移动读写位置的位移数.
__offset与__whence有关:
- 如果
__whence
是SEEK_SET
,则该文件偏移量为文件头+offset
个字节,offset
可正可负 - 如果
__whence
是SEEK_CUR
,则该文件偏移量为当前值+offset
个字节,offset
可正可负 - 如果
__whence
是SEEK_END
,则该文件偏移量为文件尾+offset
个字节,offset
可正可负
返回值:
- 如果
lseek
成功执行,则返回新的文件偏移量。 - 如果文件描述符指向一个管道、FIFO、tty 、或者网络套接字,则
lseek
返回-1, 并将errno
设置为ESPIPE
错误:
- EBADF fd不是一个打开的文件描述符。
- EINVAL whence不是SEEK_SET,SEEK_CUR,SEEK_END其中之一;或者产生的文件偏移量是负的,或超出设备的可搜索范围。
- OVERFLOW 由此产生的文件偏移超过了off_t。
- ESPIPE fd是与管道,套接字,或FIFO相关的。
我们来看个例子:下面例子测试标准输入被设置偏移量
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
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
lseek64
当需要在大于2G的文件中跳转或在更大的块设备中跳转的时候lseek
是无法完成任务的,这需要其他的文件跳转系统调用。
Linux内核驱动函数llseek
就可以完成这样的操作
#include <sys/types.h>
#include <unistd.h>
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 <sys/types.h>
#include <unistd.h>
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
注意宏添加在头文件前,不然依然报错
ftell、fseek
/*
* 功能: 设置文件位置为给定流 stream 的文件的开头
* 参数: stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流
*/
void rewind(FILE *stream)
#include <stdio.h>
/*
* 功能: 返回给定流 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 <stdio.h>
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);
}
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() 也可以用来记录多字节流式文件的状态。
举个例子:
#include <stdio.h>
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 <stdio.h>
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);
}
更多推荐
所有评论(0)