对于参数的选择,下面是必须指定一个且只能指定一个的,后面的是可选的
O_RDONLY |
只读打开 |
O_WRONLY |
只写打开 |
O_RDWR |
读、写打开 |
O_EXEC |
只执行打开 |
O_SEARCH |
只搜索打开 |
O_APPEND |
每次写时都追加到文件的尾端 |
O_CLOEXEC |
吧FD_CLOEXEC常量设置为文件描述符标志 |
O_CREAT |
若文件不存在就创建 |
O_DIRETORY |
如果path引用的不是目录,则出错 |
O_EXCL |
如果同时指定了O_CREAT,而文件已经存在则出错。 |
O_NOCTTY |
如果path引用的是终端设备,则不将该设备分配作为此进程的控制终端。 |
O_NOFOLLOW |
如果path引用的是一个符号链接,则出错 |
O_NONBLOCK |
如果path引用的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选项为文件的本次打开操作和后续的I/O操作设置非阻塞方式 |
O_SYNC |
使每次write等待物理I/O操作完成,包括由该write操作引起的文件属性更新所需的I/O。 |
O_TRUNC |
如果此文件存在,而且为只写或读-写成功打开,则将其长度截断为0 |
O_TTY_INIT |
如果打开一个还未打开的终端设备,设备非标准termios参数值 |
O_DSYNC |
使每次write要等待物理I/O操作完成,但是如果该写操作并不影响读取刚写入的数据,则不需等待文件属性被更新 |
O_RSYNC |
使每一个以文件描述符作为参数进行的read操作等待,直至所有对文件同一部分挂起的写操作都完成。 |
还有openat函数的fd参数的作用:
Openat函数的作用:
1、 让线程可以使用相对路径名打开目录中的文件
2、 可以避免time-of-check-to-time-of-use(TOCTTOU)错误。
/**
* 功能:测试对其标准输入能否设置偏移量
* 时间:2015年11月27日16:40:44
* 作者:cutter_point
*/
#include "apue.h"
#include "error.c"
int main(void)
{
//STDIN_FILENO表示标准输入,SEEK_CUR当前文件位置的漂移量+offset
if(lseek(STDIN_FILENO, 0, SEEK_CUR) == -1)
{
printf("cannot seek\n");
}//if
else
{
printf("seek OK\n");
}//else
exit(0);
}
结果:
/**
* 功能:创建一个具有空洞的文件
* 时间:2015年11月27日17:14:28
* 作者:cutter_point
*/
#include "apue.h"
#include "error.c"
#include
char buf1[] = "abcdefghij";
char buf2[] = "ABCDEFGHIJ";
int main(void)
{
int fd; //文件标识号
//这里FILE_MODE的作用是设定文件的权限,允许用户读写,组成员只读和其他用户只读权限也就是0644,-rw-r--r--
if((fd = creat("file.hole", FILE_MODE)) < 0)
err_sys("creat error");
//write根据文件标识fd从buf1中读取10个字符到文件中
if(write(fd, buf1, 10) != 10)
err_sys("buf1 write error");
//现在文件偏移量为10
//重新设定文件偏移量
if(lseek(fd, 16384, SEEK_SET) == -1)
err_sys("buf2 write error");
//文件偏移变为16384
if(write(fd, buf2, 10) != 10)
err_sys("buf2 write error");
//文件偏移为16394
exit(0);
}
结果:
好,我们看看文件里面到底是什么数据
命令行中-c标志表示以字符方式打印文件内容
Ssize_t 返回字节记数的函数
/**
* 功能:用read和write函数复制一个文件。
* 时间:2015年11月27日17:40:24
* 作者:cutter_point
*/
#include "apue.h"
#include "error.c"
#define BUFFSIZE 4096
int main(void)
{
int n;
char buf[BUFFSIZE]; //数据缓冲
//从标准输入读入数据
while((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
{
if(write(STDOUT_FILENO, buf, n) != n)
err_sys("写入文件错误");
}//while
if(n < 0)
err_sys("数据读取错误"); //如果我们最后写入的字节数小于0,而跳出的话,说明读取数据失败
exit(0);
}
结果:
那么我们应该如何设定BUFFSIZE比较好呢?
Unix系统支持在不同的进程间共享打开文件。
如果多进程打开同一文件的话
If(lseek(fd, OL, 2) < 0)//这里的2表示SEEK_END,也就是文件的长度加OL,到达文件的末尾
Err_sys(“lseekerror”);
If(write(fd, buf, 100) != 100)
Err_sys(“writeerror”);
以前的时候我们用这种方式吧数据添加到文件的末尾
但是:
相当于给文件上锁
F_DUPFD |
复制文件描述符fd。新文件描述符作为函数值返回。他是尚未打开的各描述符中大于或等于第三个参数值中各值得最小值 |
F_DUPFD_CLOEXEC |
复制文件描述符,设置与新描述符关联的FD_CLOEXEC文件描述符标志的值,返回新文件描述符 |
F_GETFD |
对应于fd的文件描述符标志作为函数值返回。 |
F_SETFD |
对于fd设置文件描述符 |
F_GETFL |
对应于fd的文件状态标志作为函数值返回。 |
F_SETFL |
将文件状态标志设置为第三个参数的值。可以更改的几个标志是:O_APPEND、O_NONBLOCK、O_SYNC、O_DSYNC、O_RSYNC、O_FSYNC和O_ASYNC |
F_GETOWN |
获取当前接收SIGIO和SIGURG信号的进程ID或进程组ID |
F_SETOWN |
设置接收SIGIO和SIGURG信号的进程ID或进程组ID。 |
实例:
/**
* 功能:第一个参数指定文件描述符,并对该描述符打印其所选择的文件标志说明
* 时间:2015年11月28日16:59:54
* 作者:cutter_point
*/
#include "apue.h"
#include "error.c"
#include
int main(int argc, char *argv[])
{
int val; //用来获取文件的对应fd的文件描述符标志
if(argc != 2)
err_quit("少了文件描述符");
if((val = fcntl(atoi(argv[1]), F_GETFL, 0)) < 0)
err_sys("fcntl错误的fd:%d", atoi(argv[1]));
switch(val & O_ACCMODE)
{
case O_RDONLY:
printf("只读");
break;
case O_WRONLY:
printf("只写");
break;
case O_RDWR:
printf("读写");
break;
default:
err_dump("未知描述符");
}//switch
if(val & O_APPEND)
printf(", append");
if(val & O_NONBLOCK)
printf(", nonblocking");
if(val & O_FSYNC)
printf(", synchronous writes");
//O_FSYNC两个都是等待写完成,但是O_FSYNC是仅仅FreeBSD和Mac OS X
#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC != O_SYNC)
if(val & O_FSYNC)
printf(", synchronous writes");
#endif
putchar('\n');
exit(0);
}
结果:
5<>temp.foo表示在文件描述符5上打开文件temp.foo以供读写
/**
* 功能:对一个文件描述符设置一个或多个文件状态标志的函数
* 时间:2015年11月28日17:17:46
* 作者:cutter_point
*/
#include "apue.h"
#include "error.c"
#include
void set_fl(int fd, int flags)
{
int val;
if((val = fcnl(fd, F_GETFL, 0)) < 0)
err_sys("fcntl F_GETFL error");
val |= flags;
if(fcntl(fd, F_SETFL, val) < 0)
err_sys("fcntl F_SETFL error");
}
具体使用,我们日后详谈
这里打开0号标志,返回一个新的描述符。