6-改变文件偏移量—lseek函数

1. 文件偏移

   通常调用read或write每读写一个字节,就会改变文件的读写位置。而在linux中同样也可以使用lseek函数来修改文件偏移量,即读写位置。

   不知道大家是否还有印象没,其实标准C库的fseek函数和系统函数lseek比较类似,fseek函数也可以移动当前读写位置(或者叫偏移量),其实fseek就是对lseek系统函数封装后实现的,快速回忆一下之前学习的fseek函数的作用及常用参数。

2. lseek函数

函数原型:

#include <sys/types.h>
#include <unistd.h> 
off_t lseek(int fd, off_t offset, int whence); 

参数说明:
fd : 文件描述符

offset : 文件偏移量(offset为负值表示往前偏移,正值则表示往后偏移)

whence : 偏移位置(SEEK_SET,SEEK_CUR,SEEK_END)
  1. SEEK_SET表示从文件开头位置往后移动offset个字节,且offset只能为正数,如果offset为负数是没有意义的。

  2. SEEK_CUR表示从当前文件的位置往前或往后移动offset个字节,如果offset为正数则表示往后移动,为负数则表示往前移动。

  3. SEEK=END表示从文件末尾的位置往前或往后移动offset个字节,如果offset为正数则表示往后移动为负数则表示往前移动。

这里写图片描述
图中说明了whence参数

这里给一些lseek函数的一些例子,注释说明了文件偏移量到的具体位置:
  lseek(fd , 0 , SEEK_SET); //文件开始位置
  lseek(fd , 0 , SEEK_END); //文件末尾位置
  lseek(fd , 10 , SEEK_END); //从文件末尾往后移动10个字节
  lseek(fd , -10 , SEEK_END); //从文件末尾往前移动10个字节
  lseek(fd , 100 , SEEK_SET); //从文件开始往后移动100个字节

返回值说明:
  成功返回文件当前读写位置相对于文件开始位置的偏移量(字节数),如果文件读写的位置是在末尾的话,返回值就是文件头与文件尾之间的字节数,也就是文件大小。失败返回-1并设置errno

注意几点:
  1. 如果文件偏移量往回超出文件头位置,则返回-1,文件指针不变,还是处于原来的位置。

  2. lseek并不适用与所有的文件类型,也就是说在管道,FIFO,socket或终端不能使用lseek函数,一旦调用将会失败,并设置errno为EPIPE。



lseek示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

int main(void) 
{
    int fd, n;
    char buf[] = "hello world test \n";
    char ch;

    fd = open("test.txt", O_RDWR|O_CREAT, 0644);
    if(fd < 0)
{
        perror("open lseek.txt error");
        exit(1);
    }
    //使用fd对打开的文件进行写操作,写完后文件指针位置位于文件结尾处
    write(fd, buf, strlen(buf));   
    /*
    注意:读和写操作使用同一偏移位置,由于文件指针位于末尾,
    因此后面的read就会读不到数据了
    这一行的目的是把文件指针移动到文件头位置,这样下面的代码就能读到数据了
    */
    lseek(fd , 0 , SEEK_SET);
if(n == -1)
{
    perror("lseek fail");
    exit(1);
}
//lseek移到文件开头,read就能读取到数据了
    while((n = read(fd, &ch, 1)))
{
        if(n < 0)
{
            perror("read error");
            exit(1);
        }
//将文件内容按字节读出,写到屏幕
        write(STDOUT_FILENO, &ch, n);  
    }
    close(fd);
    return 0;
}

在这个例子中,需要注意一点,读操作和写操作是共享同一文件偏移位置

3. 通过lseek计算文件大小

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

int main(void)
{
    int fd;
    char buf[] = "hello world"; 
    fd = open("lseek.txt", O_RDWR | O_CREAT, 0664);
    if(fd < 0){
        perror("open lseek.txt error");
        exit(1);
    }
    write(fd , buf , strlen(buf));
    //lseek函数会从起始位置开始算到文件末尾,就能求出文件的长度了
    int len = lseek(fd, 0, SEEK_END);
    if(len == -1){
        perror("lseek error");
        exit(1);
    }
    //lseek函数的返回值就是文件的大小
    printf("file len = %d\n", len);
    close(fd);
    return 0;
}

执行结果:

这里写图片描述

  需要注意的是lseek函数返回的偏移量总是相对于文件头而言,当我们把文件的偏移量移到文件末尾的话,那么lseek函数就会从文件头开始计算偏移量,直到文件末尾,最后返回的值自然就是文件的大小了。

猜你喜欢

转载自blog.csdn.net/qq_35733751/article/details/80709783