专题5 低级文件编程

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_RDLCKF_WRLCKF_UNLCK

    short l_whence;//SEEK_SETSEEK_CURSEEK_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;

 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值