dup和dup2
可以复制文件描述符,但不复制文件表。
dup 返回当前可用描述符的最小值。
dup2 可以 指定文件描述符的值,如果这个值正在使用,关闭正在使用的之后再完成复制。
dup3
注解:
dup: 系统指定最小可用的描述值
dup2: 可自己指定文件描述符,如它被占用,强制关闭再使用
int fd = open("a.txt",O_RDWR|O_CREAT|O_TRUNC,0666);
int fd2 = dup(fd); // 不会复制文件表
write(fd,"1",1);
write(fd2,"2",1);//如果覆盖 复制了 文件表
int fd3 = dup2(fd,100);
write(fd3,"3",1);
// 文件中显示:123
// 说明了它们在内存中共用一个文件偏移指针,也就是说它们只复制了文件描述符并不复制文件表
- int fcntl(int fd,int cmd, …)
+ cmd常见用法:
- F_DUPFD 复制文件描述符
- F_GETFL/F_SETFL 设置/取得 文件表的状态(不是全部)
- F_SETLK/F_GETLK/F_SETLKW 文件锁的操作
// 复制文件描述符
/*
和dup2方法类似,区别在于它不会强制关闭已被占用的文件描述符,而是给予其大于指定的值
*/
int fd2 = fcntl(fd,F_DUPFD,5); // 复制
printf("fd2=%d\n",fd2); // 不会强制关闭已经打开的
int fd3 = fcntl(fd,F_DUPFD,5); // 如果5已经被占用
printf("fd3=%d\n",fd3); // 使用大于等于参数的描述符
-------------------
// 获取文件状态标识
flags = fcntl(fd,F_GETFL);
if(flags&O_RDWR)
printf("RDWR\n");
// 修改,只有O_APPEND可以被修改,权限和创建标示都不能修改
/*
F_SETFL (int)
Set the file status flags to the value specified by arg. File access
mode (O_RDONLY, O_WRONLY, O_RDWR) and file creation flags (i.e.,
O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored. On Linux this
command can change only the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and
O_NONBLOCK flags. It is not possible to change the O_DSYNC and O_SYNC
flags; see BUGS, below.
*/
fcntl(fd,F_SETFL,O_RDWR|O_APPEND);
-------------------
获取文件状态
O_LARGEFILE 01000000
读写权限宏定义
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
flags & 0xFF 取后8位
flags & 0x11 取后2位(相当于flags & 3)
错误:由于没有加上括号,导致 先判断3==1为0,然后flags&0,结果为0,永远无法进入判断分支
if (flags & 3 == 1) {
}
正确用法: 自身要加上括号
if ((flags & 3) == 1) {
}
由于 多个进程/线程 同时写文件时,可能出现 互相覆盖的问题,导致 数据错误。
解决方案
文件锁
struct flock{
short l_type; // 锁的类型,分为 读锁 F_RDLCK、写锁F_WRLCK 和 释放锁 F_UNLCK
short l_whence; // 锁的偏移量 出发点,一般 SEEK_SET
int l_start; // 锁的偏移量
int l_len; // 锁定的长度
pid_t l_pid; // 加锁的进程ID,为F_GETLK服务,一般-1
};
读锁(F_RDLCK)
写锁(F_WRLCK)
- 如果 当前进程 加了读锁,其它 进程 可以加读锁,不能加写锁;
- 如果 当前进程 加了写锁,其它进程 不可以加锁。
- 用 F_SETLK 方式加锁,如果加不上,返回-1(非阻塞)。
- 用 F_SETLKW 方式加锁,如果加不上,等待解锁后继续执行。(阻塞)
l_whence和l_start 联合决定 锁定的 起始位置,l_len 决定了锁定的 长度。
文件锁 只是在内存中的设定,不会真正影响文件。即使程序加了文件锁,用vi之类的编辑器可以修改文件。
开发时,读写文件 应该 先加 对应的锁,然后 在read或者write。(多进程或多线程时)
F_GETLK
sync 将所有修改过的缓冲区排入写队列,并不等于实际写磁盘
fsync 只对一个文件,并且等实际写磁盘完成才返回
fdatasync 只更新数据,不更新文件属性
stat: 只使用文件路径,不需要fd
fstat:需要使用文件描述符,所以使用它之前还要open获取fd
lstat
#include
int access(const char *pathname, int mode);
0 success
-1 error errno
星际译王 - Linux专用翻译软件
Unix环境高级编程