参考资料.docx
- 文档编号:30685701
- 上传时间:2023-08-19
- 格式:DOCX
- 页数:21
- 大小:26.25KB
参考资料.docx
《参考资料.docx》由会员分享,可在线阅读,更多相关《参考资料.docx(21页珍藏版)》请在冰豆网上搜索。
参考资料
章节一openreadwrite
open(打开文件)
相关函数read,write,fcntl,close,link,stat,umask,unlink,fopen
表头文件#include
#include
#include
定义函数intopen(constchar*pathname,intflags);
intopen(constchar*pathname,intflags,mode_tmode);
函数说明参数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_IRWXG00070权限,代表该文件用户组具有可读、可写及可执行的权限。
S_IRGRP00040权限,代表该文件用户组具有可读的权限。
S_IWGRP00020权限,代表该文件用户组具有可写入的权限。
S_IXGRP00010权限,代表该文件用户组具有可执行的权限。
S_IRWXO00007权限,代表其他用户具有可读、可写及可执行的权限。
S_IROTH00004权限,代表其他用户具有可读的权限
S_IWOTH00002权限,代表其他用户具有可写入的权限。
S_IXOTH00001权限,代表其他用户具有可执行的权限。
返回值若所有欲核查的权限都通过了检查则返回0值,表示成功,只要有一个权限被禁止则返回-1。
错误代码EEXIST参数pathname所指的文件已存在,却使用了O_CREAT和O_EXCL旗标。
EACCESS参数pathname所指的文件不符合所要求测试的权限。
EROFS欲测试写入权限的文件存在于只读文件系统内。
EFAULT参数pathname指针超出可存取内存空间。
EINVAL参数mode不正确。
ENAMETOOLONG参数pathname太长。
ENOTDIR参数pathname不是目录。
ENOMEM核心内存不足。
ELOOP参数pathname有过多符号连接问题。
EIOI/O存取错误。
附加说明使用access()作用户认证方面的判断要特别小心,例如在access()后再作open()空文件可能会造成系统安全上的问题。
范例#include
#include
#include
#include
main()
{
intfd,size;
chars[]=”LinuxProgrammer!
\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);
}
执行LinuxProgrammer!
read(由已打开的文件读取数据)
相关函数readdir,write,fcntl,close,lseek,readlink,fread
表头文件#include
定义函数ssize_tread(intfd,void*buf,size_tcount);
函数说明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
定义函数intsync(void)
函数说明sync()负责将系统缓冲区数据写回磁盘,以确保数据同步。
返回值返回0。
write(将数据写入已打开的文件内)
相关函数open,read,fcntl,close,lseek,sync,fsync,fwrite
表头文件#include
定义函数ssize_twrite(intfd,constvoid*buf,size_tcount);
函数说明write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。
当然,文件读写位置也会随之移动。
返回值如果顺利write()会返回实际写入的字节数。
当有错误发生时则返回-1,错误代码存入errno中。
错误代码EINTR此调用被信号所中断。
EAGAIN当使用不可阻断I/O时(O_NONBLOCK),若无数据可读取则返回此值。
EADF参数fd非有效的文件描述词,或该文件已关闭。
章节二lseek
#include
#include
定义函数:
off_t lseek(intfildes, 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时,参数offset允许负值的出现
下列是较特别的使用方式:
1)欲将读写位置移到文件开头时:
lseek(int fildes,0,SEEK_SET)
2)欲将读写位置移到文件尾时时:
lseek(intfildes,0,SEEK_END)
3)欲将取得目前文件位置时:
lseek(intfildes,0,SEEK_CUR)
返回值:
当调用成功时则返回目前的读写位置,也就是距离文件开头多少个字符。
若有错误则返回-1,errno会存放错误代码。
章节三dupdup2
(1)每个进程在进程表中都有一个记录项,每个记录项中有一张打开文件描述符表,可将视为一个矢量,每个描述符占用一项。
与每个文件描述符相关联的是:
(a)文件描述符标志。
(b)指向一个文件表项的指针。
(2)内核为所有打开文件维持一张文件表。
每个文件表项包含:
(a)文件状态标志(读、写、增写、同步、非阻塞等)。
(b)当前文件位移量。
(c)指向该文件v节点表项的指针。
图示:
文件描述符表
------------
fd00|p0------------->文件表0--------->vnode0
------------
fd11|p1------------->文件表1--------->vnode1
------------
fd22|p2
------------
fd33|p3
------------
......
......
------------
一、单个进程内的dup和dup2
假设进程A拥有一个已打开的文件描述符fd3,它的状态如下:
进程A的文件描述符表(beforedup2)
------------
fd00|p0
------------
fd11|p1------------->文件表1--------->vnode1
------------
fd22|p2
------------
fd33|p3------------->文件表2--------->vnode2
------------
......
......
------------
经下面调用:
n_fd=dup2(fd3,STDOUT_FILENO);后进程状态如下:
进程A的文件描述符表(afterdup2)
------------
fd00|p0
------------
n_fd1|p1------------
------------\
fd22|p2\
------------_\|
fd33|p3------------->文件表2--------->vnode2
------------
......
......
------------
解释如下:
n_fd=dup2(fd3,STDOUT_FILENO)表示n_fd与fd3共享一个文件表项(它们的文件表指针指向同一个文件表项),n_fd在文件描述符表中的位置为STDOUT_FILENO的位置,而原先的STDOUT_FILENO所指向的文件表项被关闭,我觉得上图应该很清晰的反映出这点。
按照上面的解释我们就可以解释CU中提出的一些问题:
(1)"dup2的第一个参数是不是必须为已打开的合法filedes?
"--答案:
必须。
(2)"dup2的第二个参数可以是任意合法范围的filedes值么?
"--答案:
可以,在Unix其取值区间为[0,255]。
另外感觉理解dup2的一个好方法就是把fd看成一个结构体类型,就如上面图形中画的那样,我们不妨把之定义为:
structfd_t{
intindex;
filelistitem*ptr;
};
然后dup2匹配index,修改ptr,完成dup2操作。
在学习dup2时总是碰到“重定向”一词,上图完成的就是一个“从标准输出到文件的重定向”,经过dup2后进程A的任何目标为STDOUT_FILENO的I/O操作如printf等,其数据都将流入fd3所对应的文件中。
下面是一个例子程序:
#defineTESTSTR"Hellodup2\n"
intmain(){
intfd3;
fd3=open("testdup2.dat",0666);
if(fd<0){
printf("openerror\n");
exit(-1);
}
if(dup2(fd3,STDOUT_FILENO)<0){
printf("errindup2\n");
}
printf(TESTSTR);
return0;
}
其结果就是你在testdup2.dat中看到"Hellodup2"。
二、重定向后恢复
CU上有这样一个帖子,就是如何在重定向后再恢复原来的状态?
首先大家都能想到要保存重定向前的文件描述符。
那么如何来保存呢,象下面这样行么?
ints_fd=STDOUT_FILENO;
intn_fd=dup2(fd3,STDOUT_FILENO);
还是这样可以呢?
ints_fd=dup(STDOUT_FILENO);
intn_fd=dup2(fd3,STDOUT_FILENO);
这两种方法的区别到底在哪呢?
答案是第二种方案才是正确的,分析如下:
按照第一种方法,我们仅仅在"表面上"保存了相当于fd_t(按照我前面说的理解方法)中的index,而在调用dup2之后,ptr所指向的文件表项由于计数值已为零而被关闭了,我们如果再调用dup2(s_fd,fd3)就会出错(出错原因上面有解释)。
而第二种方法我们首先做一下复制,复制后的状态如下图所示:
进程A的文件描述符表(afterdup)
------------
fd00|p0
------------
fd11|p1------------->文件表1--------->vnode1
------------/|
fd22|p2/
------------/
fd33|p3------------->文件表2--------->vnode2
------------/
s_fd4|p4------/
------------
......
......
------------
调用dup2后状态为:
进程A的文件描述符表(afterdup2)
------------
fd00|p0
------------
n_fd1|p1------------
------------\
fd22|p2\
------------_\|
fd33|p3------------->文件表2--------->vnode2
------------
s_fd4|p4------------->文件表1--------->vnode1
------------
......
......
------------
dup(fd)的语意是返回的新的文件描述符与fd共享一个文件表项。
就如afterdup图中的s_fd和fd1共享文件表1一样。
确定第二个方案后重定向后的恢复就很容易了,只需调用dup2(s_fd,n_fd);即可。
下面是一个完整的例子程序:
#defineTESTSTR"Hellodup2\n"
#defineSIZEOFTESTSTR11
intmain(){
intfd3;
ints_fd;
intn_fd;
fd3=open("testdup2.dat",0666);
if(fd3<0){
printf("openerror\n");
exit(-1);
}
/*复制标准输出描述符*/
s_fd=dup(STDOUT_FILENO);
if(s_fd<0){
printf("errindup\n");
}
/*重定向标准输出到文件*/
n_fd=dup2(fd3,STDOUT_FILENO);
if(n_fd<0){
printf("errindup2\n");
}
write(STDOUT_FILENO,TESTSTR,SIZEOFTESTSTR);/*写入testdup2.dat中*/
/*重定向恢复标准输出*/
if(dup2(s_fd,n_fd)<0){
printf("errindup2\n");
}
write(STDOUT_FILENO,TESTSTR,SIZEOFTESTSTR);/*输出到屏幕上*/
return0;
}
注意这里我在输出数据的时候我是用了不带缓冲的write库函数,如果使用带缓冲区的printf,则最终结果为屏幕上输出两行"Hellodup2",而文件testdup2.dat中为空,原因就是缓冲区作怪,由于最终的目标是屏幕,所以程序最后将缓冲区的内容都输出到屏幕。
三、父子进程间的dup/dup2
由fork调用得到的子进程和父进程的相同文件描述符共享同一文件表项,如下图所示:
父进程A的文件描述符表
------------
fd00|p0
------------
fd11|p1------------->文件表1--------->vnode1
------------/|\
fd22|p2|
------------|
|
子进程B的文件描述符表|
------------|
fd00|p0|
------------|
fd11|p1---------------------|
------------
fd22|p2
------------
所以恰当的利用dup2和dup可以在父子进程之间建立一条“沟通的桥梁”。
这里不详述。
章节四fcntl
功能描述:
根据文件描述词来操作文件的特性。
文件控制函数
fcntl--filecontrol
LIBRARY
StandardCLibrary(libc,-lc)
SYNOPSIS
#include
intfcntl(intfd,intcmd);
intfcntl(intfd,intcmd,longarg);
intfcntl(intfd,intcmd,structflock*lock);
[描述]
Fcntl()针对(文件)描述符提供控制.参数fd是被参数cmd操作(如下面的描述)的描述符.
针对cmd的值,fcntl能够接受第三个参数intarg
fcntl函数有5种功能:
1.复制一个现有的描述符(cmd=F_DUPFD).
2.获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
3.获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
4.获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
5.获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW).
cmd值:
F_DUPFD 返回一个如下描述的(文件)描述符:
o 最小的大于或等于arg的一个可用的描述符
o 与原始操作符一样的某对象的引用
o 如果对象是文件(file)的话,返回一个新的描述符,这个描述符与arg共享相同的偏移量(offset)
o 相同的访问模式(读,写或读/写)
o 相同的文件状态标志(如:
两个文件描述符共享相同的状态标志)
o 与新的文件描述符结合在一起的close-on-exec标志被设置成交叉式访问execve
(2)的系统调用
F_GETFD 取得与文件描述符fd联合close-on-exec标志,类似FD_CLOEXEC.如果返回值和FD_CLOEXEC进行与运算结果是0的话,文件保持交叉式访问exec(),否则如果通过exec运行的话,文件将被关闭(arg被忽略)
F_SETFD 设置close-on-exec旗标。
该旗标以参数arg的FD_CLOEXEC位决定。
F_GETFL 取得fd的文件状态标志,如同下面的描述一样(arg被忽略)
F_SETFL 设置给arg描述符状态标志,可以更改的几个标志是:
O_APPEND,O_NONBLOCK,O_SYNC和O_ASYNC。
F_GETOWN 取得当前正在接收SIGIO或者SIGURG信号的进程id或进程组id,进程组id返回成负值(arg被忽略)
F_SET
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 参考资料