相关函数 open,fcntl,shutdown,unlink,fclose
表头文件 #include<unistd.h>
定义函数 int close(int fd)
函数说明 当使用完文件后若已不再需要则可使用close()关闭该文件,二close()会让数据写回磁盘,并释放该文件所占用的资源。参数fd为先前由open()或creat()所返回的文件描述词。
返回值 若文件顺利关闭则返回0,发生错误时返回-1。
错误代码 EBADF 参数fd 非有效的文件描述词或该文件已关闭。
附加说明 虽然在进程结束时,系统会自动关闭已打开的文件,但仍建议自行关闭文件,并确实检查返回值。
范例 参考open()
creat(建立文件)
相关函数 read,write,fcntl,close,link,stat,umask,unlink,fopen
表头文件 #include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
定义函数 int creat(const char * pathname, mode_tmode)
函数说明 参数pathname指向欲建立的文件路径字符串。Creat()相当于使用下列的调用方式调用open()
open(const char * pathname ,(O_CREAT|O_WRONLY|O_TRUNC))
错误代码 关于参数mode请参考open()函数。
返回值 creat()会返回新的文件描述词,若有错误发生则会返回-1,并把错误代码设给errno。
EEXIST 参数pathname所指的文件已存在。
EACCESS 参数pathname 所指定的文件不符合所要求测试的权限
EROFS 欲打开写入权限的文件存在于只读文件系统内
EFAULT 参数pathname 指针超出可存取的内存空间
EINVAL 参数mode 不正确。
ENAMETOOLONG 参数pathname太早祥长。
ENOTDIR 参数pathname为一目录
ENOMEM 核心内存不足
ELOOP 参数pathname有过多符号连接陆腔搏问题。
EMFILE 已达到进程可同时打开的文件数上限
ENFILE 已达到系统可同时打开的文件数上限
附加说明 creat()无法建立特别的装置文件,如果需要请使用mknod()。
范例 请参考open()。
dup(复制文件描述词)
相关函数 open,close,fcntl,dup2
表头文件 #include<unistd.h>
定义函数 int dup (int oldfd)
函数说明 dup()用来复制参数oldfd所指的文件描述词,并将它返回。此新的文件描述词和参数oldfd指的是同一个文件,共享所有的锁定、读写位置和各项权限或旗标。例如,当利用lseek()对某个文件描述词作用时,另一个文件描述词的读写位置也会随着改变。不过,文件描述词之间并不共享close-on-exec旗标。
返回值 当复制成功时,则返回最小及尚未使用的文件描述词。若有错误则返回-1,errno会存放错误代码。错误代码EBADF参数fd非圆扰有效的文件描述词,或该文件已关闭。
dup2(复制文件描述词)
相关函数 open,close,fcntl,dup
表头文件 #include<unistd.h>
定义函数 int dup2(int odlfd,int newfd)
函数说明 dup2()用来复制参数oldfd所指的文件描述词,并将它拷贝至参数newfd后一块返回。若参数newfd为一已打开的文件描述词,则newfd所指的文件会先被关闭。dup2()所复制的文件描述词,与原来的文件描述词共享各种文件状态,详情可参考dup()。
返回值 当复制成功时,则返回最小及尚未使用的文件描述词。若有错误则返回-1,errno会存放错误代码。
附加说明 dup2()相当于调用fcntl(oldfd,F_DUPFD,newfd);请参考fcntl()。
错误代码 EBADF 参数fd 非有效的文件描述词,或该文件已关闭
fcntl(文件描述词 *** 作)
相关函数 open,flock
表头文件 #include<unistd.h>
#include<fcntl.h>
定义函数 int fcntl(int fd , int cmd)
int fcntl(int fd,int cmd,long arg)
int fcntl(int fd,int cmd,struct flock * lock)
函数说明 fcntl()用来 *** 作文件描述词的一些特性。参数fd代表欲设置的文件描述词,参数cmd代表欲 *** 作的指令。
有以下几种情况:
F_DUPFD用来查找大于或等于参数arg的最小且仍未使用的文件描述词,并且复制参数fd的文件描述词。执行成功则返回新复制的文件描述词。请参考dup2()。F_GETFD取得close-on-exec旗标。若此旗标的FD_CLOEXEC位为0,代表在调用exec()相关函数时文件将不会关闭。
F_SETFD 设置close-on-exec 旗标。该旗标以参数arg 的FD_CLOEXEC位决定。
F_GETFL 取得文件描述词状态旗标,此旗标为open()的参数flags。
F_SETFL 设置文件描述词状态旗标,参数arg为新旗标,但只允许O_APPEND、O_NONBLOCK和O_ASYNC位的改变,其他位的改变将不受影响。
F_GETLK 取得文件锁定的状态。
F_SETLK 设置文件锁定的状态。此时flcok 结构的l_type 值必须是F_RDLCK、F_WRLCK或F_UNLCK。如果无法建立锁定,则返回-1,错误代码为EACCES 或EAGAIN。
F_SETLKW F_SETLK 作用相同,但是无法建立锁定时,此调用会一直等到锁定动作成功为止。若在等待锁定的过程中被信号中断时,会立即返回-1,错误代码为EINTR。参数lock指针为flock 结构指针,定义如下
struct flcok
{
short int l_type/* 锁定的状态*/
short int l_whence/*决定l_start位置*/
off_t l_start/*锁定区域的开头位置*/
off_t l_len/*锁定区域的大小*/
pid_t l_pid/*锁定动作的进程*/
}
l_type 有三种状态:
F_RDLCK 建立一个供读取用的锁定
F_WRLCK 建立一个供写入用的锁定
F_UNLCK 删除之前建立的锁定
l_whence 也有三种方式:
SEEK_SET 以文件开头为锁定的起始位置。
SEEK_CUR 以目前文件读写位置为锁定的起始位置
SEEK_END 以文件结尾为锁定的起始位置。
返回值 成功则返回0,若有错误则返回-1,错误原因存于errno.
flock(锁定文件或解除锁定)
相关函数 open,fcntl
表头文件 #include<sys/file.h>
定义函数 int flock(int fd,int operation)
函数说明 flock()会依参数operation所指定的方式对参数fd所指的文件做各种锁定或解除锁定的动作。此函数只能锁定整个文件,无法锁定文件的某一区域。
参数 operation有下列四种情况:
LOCK_SH 建立共享锁定。多个进程可同时对同一个文件作共享锁定。
LOCK_EX 建立互斥锁定。一个文件同时只有一个互斥锁定。
LOCK_UN 解除文件锁定状态。
LOCK_NB 无法建立锁定时,此 *** 作可不被阻断,马上返回进程。通常与LOCK_SH或LOCK_EX 做OR(|)组合。
单一文件无法同时建立共享锁定和互斥锁定,而当使用dup()或fork()时文件描述词不会继承此种锁定。
返回值 返回0表示成功,若有错误则返回-1,错误代码存于errno。
fsync(将缓冲区数据写回磁盘)
相关函数 sync
表头文件 #include<unistd.h>
定义函数 int fsync(int fd)
函数说明 fsync()负责将参数fd所指的文件数据,由系统缓冲区写回磁盘,以确保数据同步。
返回值 成功则返回0,失败返回-1,errno为错误代码。
lseek(移动文件的读写位置)
相关函数 dup,open,fseek
表头文件 #include<sys/types.h>
#include<unistd.h>
定义函数 off_t lseek(int fildes,off_t offset ,int whence)
函数说明 每一个已打开的文件都有一个读写位置,当打开文件时通常其读写位置是指向文件开头,若是以附加的方式打开文件(如O_APPEND),则读写位置会指向文件尾。当read()或write()时,读写位置会随之增加,lseek()便是用来控制该文件的读写位置。参数fildes 为已打开的文件描述词,参数offset 为根据参数whence来移动读写位置的位移数。
参数 whence为下列其中一种:
SEEK_SET 参数offset即为新的读写位置。
SEEK_CUR 以目前的读写位置往后增加offset个位移量。
SEEK_END 将读写位置指向文件尾后再增加offset个位移量。
当whence 值为SEEK_CUR 或SEEK_END时,参数offet允许负值的出现。
下列是教特别的使用方式:
1) 欲将读写位置移到文件开头时:lseek(int fildes,0,SEEK_SET);
2) 欲将读写位置移到文件尾时:lseek(int fildes,0,SEEK_END);
3) 想要取得目前文件位置时:lseek(int fildes,0,SEEK_CUR);
返回值 当调用成功时则返回目前的读写位置,也就是距离文件开头多少个字节。若有错误则返回-1,errno 会存放错误代码。
附加说明 Linux系统不允许lseek()对tty装置作用,此项动作会令lseek()返回ESPIPE。
范例 参考本函数说明
mkstemp(建立唯一的临时文件)
相关函数 mktemp
表头文件 #include<stdlib.h>
定义函数 int mkstemp(char * template)
函数说明 mkstemp()用来建立唯一的临时文件。参数template 所指的文件名称字符串中最后六个字符必须是XXXXXX。Mkstemp()会以可读写模式和0600 权限来打开该文件,如果该文件不存在则会建立该文件。打开该文件后其文件描述词会返回。文件顺利打开后返回可读写的文件描述词。若果文件打开失败则返回NULL,并把错误代码存在errno 中。
错误代码 EINVAL 参数template 字符串最后六个字符非XXXXXX。EEXIST 无法建立临时文件。
附加说明 参数template所指的文件名称字符串必须声明为数组,如:
char template[ ] =”template-XXXXXX”
千万不可以使用下列的表达方式
char *template = “template-XXXXXX”
范例 #include<stdlib.h>
main( )
{
int fd
char template[ ]=”template-XXXXXX”
fd=mkstemp(template)
printf(“template = %s\n”,template)
close(fd)
}
执行 template = template-lgZcbo
open(打开文件)
相关函数 read,write,fcntl,close,link,stat,umask,unlink,fopen
表头文件 #include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
定义函数 int open( const char * pathname, int flags)
int open( const char * pathname,int flags, mode_t mode)
函数说明 参数pathname 指向欲打开的文件路径字符串。下列是参数flags 所能使用的旗标:
O_RDONLY 以只读方式打开文件
O_WRONLY 以只写方式打开文件
O_RDWR 以可读写方式打开文件。上述三种旗标是互斥的,也就是不可同时使用,但可与下列的旗标利用OR(|)运算符组合。
O_CREAT 若欲打开的文件不存在则自动建立该文件。
O_EXCL 如果O_CREAT 也被设置,此指令会去检查文件是否存在。文件若不存在则建立该文件,否则将导致打开文件错误。此外,若O_CREAT与O_EXCL同时设置,并且欲打开的文件为符号连接,则会打开文件失败。
O_NOCTTY 如果欲打开的文件为终端机设备时,则不会将该终端机当成进程控制终端机。
O_TRUNC 若文件存在并且以可写的方式打开时,此旗标会令文件长度清为0,而原来存于该文件的资料也会消失。
O_APPEND 当读写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件后面。
O_NONBLOCK 以不可阻断的方式打开文件,也就是无论有无数据读取或等待,都会立即返回进程之中。
O_NDELAY 同O_NONBLOCK。
O_SYNC 以同步的方式打开文件。
O_NOFOLLOW 如果参数pathname 所指的文件为一符号连接,则会令打开文件失败。
O_DIRECTORY 如果参数pathname 所指的文件并非为一目录,则会令打开文件失败。
此为Linux2.2以后特有的旗标,以避免一些系统安全问题。参数mode 则有下列数种组合,只有在建立新文件时才会生效,此外真正建文件时的权限会受到umask值所影响,因此该文件权限应该为(mode-umaks)。
S_IRWXU00700 权限,代表该文件所有者具有可读、可写及可执行的权限。
S_IRUSR 或S_IREAD,00400权限,代表该文件所有者具有可读取的权限。
S_IWUSR 或S_IWRITE,00200 权限,代表该文件所有者具有可写入的权限。
S_IXUSR 或S_IEXEC,00100 权限,代表该文件所有者具有可执行的权限。
S_IRWXG 00070权限,代表该文件用户组具有可读、可写及可执行的权限。
S_IRGRP 00040 权限,代表该文件用户组具有可读的权限。
S_IWGRP 00020权限,代表该文件用户组具有可写入的权限。
S_IXGRP 00010 权限,代表该文件用户组具有可执行的权限。
S_IRWXO 00007权限,代表其他用户具有可读、可写及可执行的权限。
S_IROTH 00004 权限,代表其他用户具有可读的权限
S_IWOTH 00002权限,代表其他用户具有可写入的权限。
S_IXOTH 00001 权限,代表其他用户具有可执行的权限。
返回值 若所有欲核查的权限都通过了检查则返回0 值,表示成功,只要有一个权限被禁止则返回-1。
错误代码 EEXIST 参数pathname 所指的文件已存在,却使用了O_CREAT和O_EXCL旗标。
EACCESS 参数pathname所指的文件不符合所要求测试的权限。
EROFS 欲测试写入权限的文件存在于只读文件系统内。
EFAULT 参数pathname指针超出可存取内存空间。
EINVAL 参数mode 不正确。
ENAMETOOLONG 参数pathname太长。
ENOTDIR 参数pathname不是目录。
ENOMEM 核心内存不足。
ELOOP 参数pathname有过多符号连接问题。
EIO I/O 存取错误。
附加说明 使用access()作用户认证方面的判断要特别小心,例如在access()后再作open()空文件可能会造成系统安全上的问题。
范例 #include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
main()
{
int fd,size
char s [ ]=”Linux Programmer!\n”,buffer[80]
fd=open(“/tmp/temp”,O_WRONLY|O_CREAT)
write(fd,s,sizeof(s))
close(fd)
fd=open(“/tmp/temp”,O_RDONLY)
size=read(fd,buffer,sizeof(buffer))
close(fd)
printf(“%s”,buffer)
}
执行 Linux Programmer!
read(由已打开的文件读取数据)
相关函数 readdir,write,fcntl,close,lseek,readlink,fread
表头文件 #include<unistd.h>
定义函数 ssize_t read(int fd,void * buf ,size_t count)
函数说明 read()会把参数fd 所指的文件传送count个字节到buf指针所指的内存中。若参数count为0,则read()不会有作用并返回0。返回值为实际读取到的字节数,如果返回0,表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节移动。
附加说明 如果顺利read()会返回实际读到的字节数,最好能将返回值与参数count 作比较,若返回的字节数比要求读取的字节数少,则有可能读到了文件尾、从管道(pipe)或终端机读取,或者是read()被信号中断了读取动作。当有错误发生时则返回-1,错误代码存入errno中,而文件读写位置则无法预期。
错误代码 EINTR 此调用被信号所中断。
EAGAIN 当使用不可阻断I/O 时(O_NONBLOCK),若无数据可读取则返回此值。
EBADF 参数fd 非有效的文件描述词,或该文件已关闭。
范例 参考open()。
sync(将缓冲区数据写回磁盘)
相关函数 fsync
表头文件 #include<unistd.h>
定义函数 int sync(void)
函数说明 sync()负责将系统缓冲区数据写回磁盘,以确保数据同步。
返回值 返回0。
write(将数据写入已打开的文件内)
相关函数 open,read,fcntl,close,lseek,sync,fsync,fwrite
表头文件 #include<unistd.h>
定义函数 ssize_t write (int fd,const void * buf,size_t count)
函数说明 write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。当然,文件读写位置也会随之移动。
返回值 如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。
错误代码 EINTR 此调用被信号所中断。
EAGAIN 当使用不可阻断I/O 时(O_NONBLOCK),若无数据可读取则返回此值。
EADF 参数fd非有效的文件描述词,或该文件已关闭。
范例 请参考open()。
文件锁1.fcntl()函数说明
前面讲述的5个基本函数实现了文件的打开、读/写等基本 *** 作,本节将讨论在文件已经共享的情况下如何 *** 作,也就是当多个用户共同使用、 *** 作一个文件的情况。这时,Linux通常采用的方法是给文件上锁,来避免共享的资源产生竞争的状态。
文件锁包括建议性锁和强制性锁。建议性锁要求每个上锁文件的进程都要检查是否有锁存在,并且尊重已有的锁。在一般情况下,内核和系统都不使用建议性锁。强制性锁是由内核执行的锁,当一个文件被上锁进行写入 *** 作时,内核将阻止其他任何文件对其进行读写 *** 作。采用强制性锁对性能的影响很大,每次读写 *** 作都必须检查是否有锁存在。
在Linux中,实现拿明文件上锁的函数有lockf()和fcntl(),其中lockf()用于对文件施加建议性锁,而fcntl()不仅可以施加建议性锁,还可以施加强制性锁。同时,fcntl()还能对文件的某一记录上锁,也就是记录锁。
记录锁又可分为读取锁和写入锁,其中读取锁又称为共享锁,它能够使多个进程都能在文件的同一部分建立读取锁。而写入锁又称为排斥锁,在任何时刻只能有一个进程在文件的某消晌告个部分建立写入锁。当然,在文件的同一部分不能同时建立读取锁和写入锁。
fcntl()函数具有很丰富的功能,它可以对已打开的文件描述符进行各种 *** 作,不仅包括管理文件锁,还包括获得设置文件描述符和文件描述符标志、文件描述符的复制等很多功能。本节主要介绍fcntl()函数建立记录锁的方法,关于它的其他 *** 作,感兴趣的读者可以参看fcntl手册。
2.fcntl()函数格式
用于建立记录锁的fcntl()函数语法要点如表2.6所示。
表2.6 fcntl()函数语法要点
所需头文件
#include
<sys/types.h>
#include <unistd.h>
#include <fcntl.h>
函数原型
int fcntl(int fd, int cmd, struct flock
*lock)
函数传入值
fd:文件描述符
cmd
F_DUPFD:复制文件描述符
F_GETFD:获得fd的close-on-exec标志,若标志未设置,则文件经过exec()函数之后仍保持打开状态
F_SETFD:设置close-on-exec标志,该标志由参数arg的FD_CLOEXEC位决定
F_GETFL:得到open设置的标志
F_SETFL:改变open设置的标志
F_GETLK:根据lock描述,决定是否上文件锁
F_SETLK:设置lock描述的文件锁
F_SETLKW:这是F_SETLK的阻塞版本(命令名中的W表示等待(wait))。
在无法获取锁时,会进入睡眠状态;如果可以获取锁或者捕捉到信号则会返回
lock:结构为flock,设置记录锁的具体状态,后面会详细说明
函数返回值
成功:0
1:出错
这里,lock的结构如下所示:
struct flock
{
short
l_type
off_t l_start
short l_whence
off_t
l_len
pid_t l_pid
}
lock结构中每个变量的取值含义如表2.7所示。
表2.7 lock结构变量取值
l_type
F_RDLCK:读取锁(共享锁)
F_WRLCK:写入锁(排斥锁)
F_UNLCK:解锁
l_start
加锁区域在文件中的相对位移量(字节),与l_whence值一起决定加锁区域的起始位置
l_whence:
相对位移量的起点(同lseek的whence)
SEEK_SET:当前位置为文件的开头,新位置为偏移量的大小
SEEK_CUR:当前位置为文件指针的位置,新位置为当前位置加上偏移量
SEEK_END:当前位置为文件的结尾,新位置为文件的大小加上偏移量的大小谨拍
l_len
加锁区域的长度
为加锁整个文件,通常的方法是将l_start设置为0,l_whence设置为SEEK_SET,l_len设置为0。
3.fcntl()使用实例
下面首先给出了使用fcntl()函数的文件记录锁功能的代码实现。在该代码中,首先给flock结构体的对应位赋予相应的值。
接着调用两次fcntl()函数。用F_GETLK命令判断是否可以进行flock结构所描述的锁 *** 作:若可以进行,则flock结构的l_type会被设置为F_UNLCK,其他域不变;若不可进行,则l_pid被设置为拥有文件锁的进程号,其他域不变。
用F_SETLK和F_SETLKW命令设置flock结构所描述的锁 *** 作,后者是前者的阻塞版。
当第一次调用fcntl()时,使用F_GETLK命令获得当前文件被上锁的情况,由此可以判断能不能进行上锁 *** 作;当第二次调用fcntl()时,使用F_SETLKW命令对指定文件进行上锁/解锁 *** 作。因为F_SETLKW命令是阻塞式 *** 作,所以,当不能把上锁/解锁 *** 作进行下去时,运行会被阻塞,直到能够进行 *** 作为止。
文件记录锁的功能代码具体如下所示:
/* lock_set.c */
int lock_set(int
fd, int type)
{
struct flock old_lock,
lock
lock.l_whence = SEEK_SET
lock.l_start =
0
lock.l_len = 0
lock.l_type =
type
lock.l_pid = -1
/* 判断文件是否可以上锁
*/
fcntl(fd, F_GETLK, &lock)
if (lock.l_type !=
F_UNLCK)
{
/* 判断文件不能上锁的原因 */
if
(lock.l_type == F_RDLCK) /* 该文件已有读取锁
*/
{
printf("Read lock already set by %d\n",
lock.l_pid)
}
else if (lock.l_type == F_WRLCK) /*
该文件已有写入锁 */
{
printf("Write lock already set
by %d\n", lock.l_pid)
}
}
/* l_type
可能已被F_GETLK修改过 */
lock.l_type = type
/*
根据不同的type值进行阻塞式上锁或解锁 */
if ((fcntl(fd, F_SETLKW, &lock)) <
0)
{
printf("Lock failed:type = %d\n",
lock.l_type)
return
1
}
switch(lock.l_type)
{
case
F_RDLCK:
{
printf("Read lock set by %d\n",
getpid())
}
break
case
F_WRLCK:
{
printf("Write lock set by %d\n",
getpid())
}
break
case
F_UNLCK:
{
printf("Release lock by %d\n",
getpid())
return
1
}
break
default:
break
}/*
end of switch */
return 0
}
下面的实例是文件写入锁的测试用例,这里首先创建了一个hello文件,之后对其上写入锁,最后释放写入锁。代码如下所示:
/* write_lock.c */
#include
<unistd.h>
#include <sys/file.h>
#include
<sys/types.h>
#include <sys/stat.h>
#include
<stdio.h>
#include <stdlib.h>
#include
"lock_set.c"
int main(void)
{
int
fd
/* 首先打开文件 */
fd = open("hello",O_RDWR | O_CREAT,
0644)
if(fd <0)
{
printf("Open file
error\n")
exit(1)
}
/* 给文件上写入锁
*/
lock_set(fd, F_WRLCK)
getchar()
/* 给文件解锁
*/
lock_set(fd, F_UNLCK)
getchar()
close(fd)
exit(0)
}
为了能够使用多个终端,更好地显示写入锁的作用,本实例主要在PC上测试,读者可将其交叉编译,下载到目标板上运行。下面是在PC上的运行结果。为了使程序有较大的灵活性,笔者采用文件上锁后由用户输入任意键使程序继续运行。建议读者开启两个终端,并且在两个终端上同时运行该程序,以达到多个进程 *** 作一个文件的效果。在这里,笔者首先运行终端一,请读者注意终端二中的第一句。
终端一:
$ ./write_lock
write lock set by
4994
release lock by 4994
终端二:
$ ./write_lock
write lock already
set by 4994
write lock set by 4997
release lock by 4997
由此可见,写入锁为互斥锁,同一时刻只能有一个写入锁存在。
接下来的程序是文件读取锁的测试用例,原理与上面的程序一样。
/* fcntl_read.c */
#include
<unistd.h>
#include <sys/file.h>
#include
<sys/types.h>
#include <sys/stat.h>
#include
<stdio.h>
#include <stdlib.h>
#include
"lock_set.c"
int main(void)
{
int fd
fd
= open("hello",O_RDWR | O_CREAT, 0644)
if(fd <
0)
{
printf("Open file
error\n")
exit(1)
}
/* 给文件上读取锁
*/
lock_set(fd, F_RDLCK)
getchar()
/* 给文件解锁
*/
lock_set(fd, F_UNLCK)
getchar()
close(fd)
exit(0)
}
同样开启两个终端,并首先启动终端一上的程序,其运行结果如下所示。
终端一:
$ ./read_lock
read lock set by
5009
release lock by 5009
终端二:
$ ./read_lock
read lock set by
5010
release lock by 5010
读者可以将此结果与写入锁的运行结果相比较,可以看出,读取锁为共享锁,当进程5009已设置读取锁后,进程5010仍然可以设置读取锁。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)