linux文件操作(2)



 lseek() - 用于移动文件的偏移量
   文件偏移量是什么?
  文件的读写都是一个字节一个字节的完成,因此必须记录文件中读写的位置,这个位置叫 文件指针。文件的偏移量存在文件表中,有几个文件表就有几个偏移量。
  lseek()可以直接指定文件指针的位置:
  lseek(int fd,off_t offset,int whence)
   参数:fd 文件描述符
        offset 偏移量
        whence 偏移量的起点
  真正的偏移量 由 whence和offset一起决定
   whence的值有三种:
   SEEK_SET - 从文件头开始
   SEEK_CUR - 从当前位置开始
   SEEK_END - 从文件尾开始
   最好以SEEK_SET 做开始点。

  例子

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

int main(){
  int fd = open("a.txt",O_RDWR);
  if(fd == -1) perror("open"),exit(-1);
  char ch;
  read(fd,&ch,1); printf("%c\n",ch);//a
  read(fd,&ch,1); printf("%c\n",ch);//b
  lseek(fd,3,SEEK_CUR);
  read(fd,&ch,1); printf("%c\n",ch);//f 
  lseek(fd,0,SEEK_SET);//回到开始
  write(fd,"1",1);//a
  lseek(fd,3,SEEK_SET); write(fd,"2",1);//d  
  lseek(fd,2,SEEK_CUR); write(fd,"3",1);//g
  lseek(fd,-2,SEEK_CUR); write(fd,"4",1);//f 
  lseek(fd,-3,SEEK_END); write(fd,"5",1);//s
  close(fd);
}

  dup() 和 dup2() - 复制文件描述符

   dup()函数复制文件描述符时,新的描述符由系统选择值,就是未使用的最小值。
   dup2()函数复制文件描述符时,新的描述符的值由程序员传入,如果已经被使用会先关闭然后再复制(定制)。
   注:描述符的复制都不复制文件表。

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

int main(){
  int fd = open("a.txt",O_RDWR);
  if(fd == -1) perror("open"),exit(-1);
  int fd2 = dup(fd);//只复制描述符,不复制文件表
  printf("fd=%d,fd2=%d\n",fd,fd2);
  write(fd,"1",1);
  write(fd2,"2",1);
  int fd3 = dup2(fd,100);
  printf("fd3=%d\n",fd3);//100
  int fd4 = open("b.txt",O_RDWR|O_CREAT,0666);
  printf("fd4=%d\n",fd4);//5
  int fd5 = dup2(fd,5);//关闭b.txt,打开a.txt
  printf("fd5=%d\n",fd5);//5
  write(fd5,"HEHE",4);//共用文件表,在2的后面写
  close(fd);//从文件描述符总表删除fd
}



  函数fcntl() - 可以控制文件、获取文件描述符的状态。
  int fcntl(int fd,int cmd,...)
  参数:fd 文件描述符
        cmd 操作的命名
        ... 需要什么参数由 cmd 决定
  常见的cmd包括:
   F_DUPFD - 复制文件描述符
   F_SETFL/F_GETFL - 设置/获取文件的状态
   其中,设置的时候只有 O_APPEND有效,获取的时候,O_CREAT/O_EXCL/O_TRUNC 无法获取到,只能获取权限和O_APPEND。
   F_SETLK/F_SETLKW/F_GETLK - 文件锁操作
   返回值由 cmd 确定。

  经验:有时候编程需要取某一位或某几位,用位与&运算,比如:取i的后8位,i&0xFF
  8进制和16进制其实是 二进制的简写。
  有符号整数中,最小的是?最大的是?
   int max = 0x7FFFFFFF;
   int min = 0x80000000;
 
  关于文件锁 - 有两个进程,同时写了一个文件,一定会有问题。解决方案:1 从进程的角度解决。2 从文件的角度解决问题。
  可以 使用 文件锁,在一个进程使用某个文件时,锁定这个文件。
  文件锁有读锁和写锁之分,读锁允许所有读进程操作,而锁定写文件的进程(不允许写);写锁 锁定其他进程的任意操作。
  文件锁比较细致,不是锁定整个文件,可以锁定文件的某些部分。
  Uc怎么实现的文件锁(API):
   1 定义struct flock,成员:
   struct flock{
     short l_type;//锁的类型
     short l_whence;//锁定的起点参照
     off_t l_start;//锁定的起点偏移量
     off_t l_len;//锁定区域的长度
     pid_t l_pid;//锁定进程的ID,只有F_GETLK使用,F_SETLK给 -1就可以
   };
  锁的类型包括三种:
   F_RDLCK 读锁     F_WRLCK  写锁
   F_UNLCK 释放锁
  l_whence有三个值,一般用SEEK_SET
  l_whence和l_start联合决定了锁的起点。

  文件锁其实不会锁定文件,也不锁定read()/write(),只能锁定fcntl(fd,F_SETLK),也就是说:文件锁 只能阻止 别的进程再次加锁。
  文件锁的正确用法是:
   在编写代码时,读文件之前要先加读锁,写文件之前先加写锁,加锁失败就不进行读写操作,这样文件锁才能有用。
   fcntl() 和 read() write()结合使用。
  文件加锁可以有两种方式:
   F_SETLK:如果加不上锁,直接返回-1
   F_SETLKW:如果加不上锁,等待,等到能加上这个锁为止。

  注:读写文件之前要加锁,完成读写以后要立即释放锁。

  F_GETLK是用于测试一个锁能否加上。

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

int main(){
  int fd=open("a.txt",O_RDONLY|O_CREAT|O_APPEND,
	0666);
  if(fd == -1) perror("open"),exit(-1);
  int flags = fcntl(fd,F_GETFL);//取不到O_CREAT
  printf("flags=%d\n",flags);
  //验证某一位二进制是0还是1,用 位与& 运算
  if(flags & O_CREAT) printf("CREATE\n");
  if(flags & O_APPEND) printf("APPEND\n");
  //权限比较用后两位,如何取后2位,与3位与
  if((flags&3)== O_RDWR) printf("RDWR\n");
  if((flags&3)== O_RDONLY) printf("RDONLY\n");
  printf("------------------\n");
  fcntl(fd,F_SETFL,O_RDWR);//设置,只有APPEND能改
  flags = fcntl(fd,F_GETFL);//取出新的状态
  if(flags & O_APPEND) printf("APPEND\n");
  if((flags&3)== O_RDWR) printf("RDWR\n");
  if((flags&3)== O_RDONLY) printf("RDONLY\n");
  close(fd);
}



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

int main(){
  int fd = open("a.txt",O_RDWR);
  if(fd == -1) perror("open"),exit(-1);
  struct flock lock;
  lock.l_type = F_RDLCK;//读锁  写锁是F_WRLCK
  lock.l_whence = SEEK_SET;//从头开始最简单
  lock.l_start = 0;//从文件的第一个字节开始锁定
  lock.l_len = 20;//锁定20个字节
  lock.l_pid = -1;//SETLK用不到这个参数,-1即可
  int res = fcntl(fd,F_SETLK,&lock);//上锁
  if(res == -1) perror("上锁失败\n"),exit(-1);
  else printf("成功了\n");
  sleep(20);
  printf("读文件完成了,释放读锁\n");
  lock.l_type = F_UNLCK;
  fcntl(fd,F_SETLK,&lock);//释放锁的代码
  sleep(20);
  printf("其他代码也完毕,程序结束\n");
  close(fd);
}

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

int main(){
  int fd = open("a.txt",O_RDWR);
  if(fd == -1) perror("open"),exit(-1);
  struct flock lock;
  lock.l_type = F_WRLCK;//读锁  写锁是F_WRLCK
  lock.l_whence = SEEK_SET;//从头开始最简单
  lock.l_start = 0;//从文件的第一个字节开始锁定
  lock.l_len = 20;//锁定20个字节
  lock.l_pid = -1;//SETLK用不到这个参数,-1即可
  int res = fcntl(fd,F_SETLK,&lock);//上锁
  if(res == -1) perror("上锁失败\n"),exit(-1);
  else printf("成功了\n");
  close(fd);
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值