fseek(移动文件流的读写位置)
相关函数 rewind,ftell,fgetpos,fsetpos,lseek
表头文件 #include<stdio.h>
定义函数 int fseek(FILE * stream,long offset,int whence);
函数说明 fseek()用来移动文件流的读写位置。参数stream为已打开的文件指针,参数offset为根据参数whence来移动读写位置的位移数。
参数 whence为下列其中一种:
SEEK_SET从距文件开头offset位移量为新的读写位置。SEEK_CUR 以目前的读写位置往后增加offset个位移量。
SEEK_END将读写位置指向文件尾后再增加offset个位移量。
当whence值为SEEK_CUR 或SEEK_END时,参数offset允许负值的出现。
下列是较特别的使用方式:
1) 欲将读写位置移动到文件开头时:fseek(FILE *stream,0,SEEK_SET);
2) 欲将读写位置移动到文件尾时:fseek(FILE *stream,0,0SEEK_END);
返回值 当调用成功时则返回0,若有错误则返回-1,errno会存放错误代码。
附加说明 fseek()不像lseek()会返回读写位置,因此必须使用ftell()来取得目前读写的位置。
范例
#include<stdio.h>
int main(int argc,char *argv[])
{
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);
}
执行
offset = 5
offset =0
offset=10
ftell(取得文件流的读取位置)
相关函数 fseek,rewind,fgetpos,fsetpos
表头文件 #include<stdio.h>
定义函数 long ftell(FILE * stream);
函数说明 ftell()用来取得文件流目前的读写位置。参数stream为已打开的文件指针。
返回值 当调用成功时则返回目前的读写位置,若有错误则返回-1,errno会存放错误代码。
错误代码 EBADF 参数stream无效或可移动读写位置的文件流。
范例 见上
rewind(重设文件流的读写位置为文件开头)
相关函数 fseek,ftell,fgetpos,fsetpos
表头文件 #include<stdio.h>
定义函数 void rewind(FILE * stream);
函数说明 rewind()用来把文件流的读写位置移至文件开头。参数stream为已打开的文件指针。此函数相当于调用fseek(stream,0,SEEK_SET)。
返回值 无返回值
范例 参考fseek()
lseek(移动文件的读写位置)
相关函数 dup,open,fseek
表头文件 #include<sys/types.h> #include<unistd.h>
定义函数 off_t lseek(int fildes,off_t offset ,int whence);
函数说明 每一个已打开的文件都有一个读写位置,当打开文件时通常其读写位置是指向文件开头,若是以附加的方式打开文件(如O_APPEND),则读写位置会指向文件尾。当read()或write()时,读写位置会随之增加,lseek()便是用来控制该文件的读写位置。参数fildes 为已打开的文件描述词,参数offset 为根据参数whence来移动读写位置的位移数。
参数 whence为下列其中一种:
SEEK_SET 参数offset即为新的读写位置。
SEEK_CUR 以目前的读写位置往后增加offset个位移量。
SEEK_END 将读写位置指向文件尾后再增加offset个位移量。
当whence 值为SEEK_CUR 或SEEK_END时,参数offet允许负值的出现。
下列是教特别的使用方式:
1) 欲将读写位置移到文件开头时:lseek(int fildes,0,SEEK_SET);
2) 欲将读写位置移到文件尾时:lseek(int fildes,0,SEEK_END);
3) 想要取得目前文件位置时:lseek(int fildes,0,SEEK_CUR);
返回值 当调用成功时则返回目前的读写位置,也就是距离文件开头多少个字节。若有错误则返回-1,errno 会存放错误代码。
附加说明 Linux系统不允许lseek()对tty装置作用,此项动作会令lseek()返回ESPIPE。
fstat(由文件描述词取得文件状态)
相关函数 stat,lstat,chmod,chown,readlink,utime
表头文件 #include<sys/stat.h> #include<unistd.h>
定义函数 int fstat(int fildes,struct stat *buf);
函数说明 fstat()用来将参数fildes所指的文件状态,复制到参数buf所指的结构中(struct stat)。Fstat()与stat()作用完全相同,不同处在于传入的参数为已打开的文件描述词。详细内容请参考stat()。
返回值 执行成功则返回0,失败返回-1,错误代码存于errno。
范例
#include<sys/stat.h>
#include<unistd.h>
#include<fcntk.h>
int main(int argc,char *argv[])
{
struct stat buf;
int fd;
fd = open (“/etc/passwd”,O_RDONLY);
fstat(fd,&buf);
printf(“/etc/passwd file size +%d/n “,buf.st_size);
}
执行
/etc/passwd file size = 705
lseek 函数
所有打开的文件都有一个当前文件偏移量(current file offset),以下简称为 cfo。cfo 通常是一个非负整数,用于表明文件开始处到文件当前位置的字节数。读写操作通常开始于 cfo,并且使 cfo 增大,增量为读写的字节数。文件被打开时,cfo 会被初始化为 0,除非使用了 O_APPEND 。 使用 lseek 函数可以改变文件的 cfo 。 #include <unistd.h> off_t lseek(int filedes, off_t offset, int whence); 返回值:新的偏移量(成功),-1(失败)
参数 offset 的含义取决于参数 whence: 1. 如果 whence 是 SEEK_SET,文件偏移量将被设置为 offset。 2. 如果 whence 是 SEEK_CUR,文件偏移量将被设置为 cfo 加上 offset, offset 可以为正也可以为负。 3. 如果 whence 是 SEEK_END,文件偏移量将被设置为文件长度加上 offset, offset 可以为正也可以为负。SEEK_SET、SEEK_CUR 和 SEEK_END 是 System V 引入的,在这之前使用的是 0、1 和 2。 lseek 的以下用法返回当前的偏移量: off_t currpos; currpos = lseek(fd, 0, SEEK_CUR); 这个技巧也可用于判断我们是否可以改变某个文件的偏移量。如果参数 fd(文件描述符)指定的是 pipe(管道)、FIFO 或者 socket,lseek 返回 -1 并且置 errno 为 ESPIPE。 对于普通文件(regular file),cfo 是一个非负整数。但对于特殊设备,cfo 有可能是负数。因此,我们不能简单地测试 lseek 的返回值是否小于 0 来判断 lseek 成功与否,而应该测试 lseek 的返回值是否等于 -1 来判断 lseek 成功与否。 lseek 仅将 cfo 保存于内核中,不会导致任何 I/O 操作。这个 cfo 将被用于之后的读写操作。 如果 offset 比文件的当前长度更大,下一个写操作就会把文件“撑大(extend)”。这就是所谓的在文件里创造“空洞(hole)”。没有被实际写入文件的所有字节由重复的 0 表示。空洞是否占用硬盘空间是由文件系统(file system)决定的。 以下程序创建一个有空洞的文件: /* Standard C header */ #include <stdio.h> /* Unix header */ #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> char buf1[] = "abcdefghij"; char buf2[] = "ABCDEFGHIJ"; int main(void) { int fd, size; if ((fd = creat("file.hole", S_IRUSR|S_IWUSR)) < 0) { printf("creat error/n"); return -1; } size = sizeof buf1 - 1; if (write(fd, buf1, size) != size) { printf("buf1 write error/n"); return -1; } /* offset now = 10 */ if (lseek(fd, 16384, SEEK_SET) == -1) { printf("lseek error/n"); return -1; } /* offset now = 16384 */ size = sizeof buf2 - 1; if (write(fd, buf2, size) != size) { printf("buf2 write error/n"); return -1; } /* offset now = 16394 */ return 0; } 运行结果: $ ./a.out ???$ ls -l file.hole // 查看文件大小 -rw-r--r-- 1 sar 16394 Nov 25 01:01 file.hole ???$ od -c file.hole // 查看文件实际内容 0000000 a b c d e f g h i j /0 /0 /0 /0 /0 /0 0000020 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 * 0040000 A B C D E F G H I J 0040012 -c 选项告诉 od 以字符模式显示文件内容。可以看到,没有被实际写入文件的所有字节都由 0 表示。每行前面的 7 个数字是文件偏移量的八进制表示形式。 为了证明 file.hole 的确有空洞,我们拿它和另一个相同大小但没有空洞的文件比较: $ ls -ls file.hole file.nohole 8 -rw-r--r-- 1 sar 16394 Nov 25 01:01 file.hole 20 -rw-r--r-- 1 sar 16394 Nov 25 01:03 file.nohole 可以看到,没有空洞的 file.nohole 占用了 20 个块(block),而 file.hole 仅占用 8 个块。 |