1. 文件的打开与创建
1.1 函数原型
#include <fcntl.h>
int open(const char *filename, int oflag, …/*[mode_t mode*/];
1.2 重要说明
oflag:只能为如下三个值:O_RDONLY O_WRONLY O_RDWR
读方式打开文件/etc/passwd
int fno;
if((fno = open(“/etc/passwd”, O_RDONLY)) >= 0)/*文件打开成功*/
755访问权限创建文件”/tmp/t1”, 如果文件存在则直接返回。
if((fno = open(“/tmp/t1”, O_WRONLY|O_CREAT|O_EXCL, 0755)) < 0) return;
计算文件的权限:
例如:假设Unix系统的umask值为0033, open函数创建权限为0666的文件,则最终创建文件的权限是?
计算过程如下:
mode = 110 110 110
~mask= 111 100 100
mod & (~mask) = 110 100 100 = 0644
PS:不可用mode – umask = 0633
2. 文件的关闭与删除
2.1 函数原型
#include <unistd.h>
int close(int fildes);
int unlink(char *path);//文件链接数减1,仅当文件链接数为0时,文件才真正删除
2.2 例子
PS:只使用一次的临时文件,可以先删除再使用,这样就不心担心忘记删除文件而造成磁盘垃圾文件了
#include <stdio.h>
#include <fcntl.h>
int main()
{
int foo;
if((foo = open("./tmpfile", O_RDWR | O_CREAT | O_EXCL, 0755)) < 0)
{
fprintf(stderr, "open file error!/n");
return;
}
unlink("./tmpfile");
sleep(10);
printf("end./n");
}
3. 文件读、写、定位与缓冲
3.1 函数原型
#include <unistd.h>
ssize_t read(int filedes, void *buff, size_t nbytes);
ssize_t write(int filedes, void *buff, size_t nbytes);
off_t lseek(int fildes, off_t offset, int whence);
int fsync(int fildes);//将所有写入文件描述符的数据真正写到磁盘或者其他设备中,类似于标准文件编程库中的函数fflush,成功时返回0,否则返回-1.
4. 文件控制
4.1 函数fcntl
管理文件低级操作,对已经打开的文件描述符进行各种控制操作,其原型如下:
#include <fcntl.h>
int fcntl(int fildes, int cmd);
int fcntl(int fildes, int cmd, int arg);
int fcntl(int fildes, int cmd, struct flock *arg);
函数fcntl对文件描述符fildes执行各种控制命令,参数cmd确定了执行具体命令和是否需要第三个附加参数“arg”。
4.2 文件锁
进程在操作文件期间,可以使用文件锁,锁定文件中的敏感部分,防止其他进程越权操作该部分数据。函数fcntl提供了对文件任意区域置锁的能力,既可以锁住全部文件,又可以锁住文件部分的记录,故文件锁又称为“记录锁”。
根据文件锁的访问方式,可以区分为读锁和写锁两种。读锁又名共享锁,它防止进程读取文件记录被更改。文件记录可以同时设置多个读锁,但当一个读锁存在时,就不能在记录处设置写锁。
写锁又名互斥锁,它用来保证文件更改记录时不被干扰,确保文件内容一致性和完整性,防止写丢失和读“脏”数据。文件记录一旦被设置了写锁,就不能再设置任意锁,除非写锁解除。
文件记录在同一刻,可以设置多个读锁,但仅能设置一个写锁,并且读、写锁不能同时存在。
struct flock
{
short l_type;//锁类型:F_RDLCK、F_WRLCK和F_UNLCK
short l_whence;//SEEK_SET、SEEK_CUR和SEEK_END
long l_start;
long l_len;//锁区域长度,0表示锁至全部文件
short l_pid;//拥有锁进程ID号
}
例如:为了锁住全部文件,应该如何设置flock结构?
答:
l_start=0;
l_len=0;
l_whence=SEEK_SET;
函数fcntl专用于锁操作时,参数cmd三种取值:
1. F_GETTLK
获取对应文件中指定区域的文件锁信息
2. F_SETFLK
设置文件锁,包括读锁、写锁和清除锁。
3. F_SETLKW
为F_SETFLK的阻塞版本。
PS:文件锁最典型应用于两个方面,一是锁定文件中的临界数据,比如并发投票时文件记录投票数;二是利用具有互斥性质的写锁,实现进程的并发控制。
4.3 文件锁操作
1. 测试锁
/**
*SeeLock:查询描述符fd对应文件从偏移start处开始的len字节中的锁信息。
*/
void SeeLock(int fd, int start, int len)
{
struct flock arg;
arg.l_type = F_WRLCK;
arg.l_whence = SEEK_SET;
arg.l_start = start;
arg.l_len = len;
if(fcntl(fd, F_GETLK, &arg) == -1)
fprintf(stderr, "See Lock failed/n");
else if(arg.l_type == F_UNLCK)
fprintf(stderr, "No lock From %d To %d/n", start, len);
else if(arg.l_type == F_WRLCK)
fprintf(stderr, "Write Lock From %d To %d, id=%d/n", start, len, arg.l_pid);
else if(arg.l_type == F_RDLCK)
fprintf(stderr, "Read Lock From %d To %d, id=%d/n", start, len, arg.l_pid);
}
2. 申请读锁
/**
*GetReadLock(int fd, int start, int len)
*本函数以阻塞模式在文件描述符fd对应的文件中申请共享锁,锁定的区域为从偏移start处开始的len字节。
*/
void GetReadLock(int fd, int start, int len)
{
struct flock arg;
arg.l_type = F_RDLCK;
arg.l_whence = SEEK_SET;
arg.l_start = start;
arg.l_len = len;
if(fcntl(fd, F_SETLKW, &arg) == -1)
fprintf(stderr, "[%d] Set Read Lock failed./n", getpid());
else
fprintf(stderr, "[%d] Set Read Lock From %d To %d/n", getpid(), start, len);
}
3. 申请写锁
/**
*本函数以阻塞模式在文本描述符fd对应的文件中申请互斥写锁,锁定的区域为从偏移start处开始的len字节
*
*/
void GetWriteLock(int fd, int start, int len)
{
struct flock arg;
arg.l_type = F_WRLCK;
arg.l_whence = SEEK_SET;
arg.l_start = start;
arg.l_len = len;
if(fcntl(fd, F_SETLKW, &arg) == -1)
fprintf(stderr, "[%d] Set Write Lock failed./n", getpid());
else
fprintf(stderr, "[%d] Set Write Lock From %d To %d/n", getpid(), start, len);
}
4. 释放锁
/**
*本函数文件描述符fd对应文件中的释放锁,释放的区域为从偏移start处开始的len字节
*
*/
void ReleaseLock(int fd, int start, int len)
{
struct flock arg;
arg.l_type = F_UNLCK;
arg.l_whence = SEEK_SET;
arg.l_start = start;
arg.l_len = len;
if(fcntl(fd, F_SETLKW, &arg) == -1)
fprintf(stderr, "[%d] UnLock failed./n", getpid());
else
fprintf(stderr, "[%d] UnLock From %d To %d/n", getpid(), start, len);
}
5. 实例
int main()
{
int fd;
struct flock arg;
if((fd = open("/tmp/tlock1", O_RDWR | O_CREAT, 0755)) < 0)
{
fprintf(stderr, "open file failed!/n");
return -1;
}
SeeLock(fd, 0, 30);
GetReadLock(fd, 0, 10); //申请读锁
SeeLock(fd, 11, 20);
GetWriteLock(fd, 11, 20); //申请写锁
sleep(30);
ReleaseLock(fd, 0, 10); //释放锁
ReleaseLock(fd, 11, 20);
return 0;
}