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
}
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); }