-----哈哈哈,小伙伴们,今天的分享是接着昨天的open函数,继续分析它里面的用法(如有错的地方,还望各位帮忙指出错误,我好纠正),好了废话不多说了,开始干货分享啦! 一、O_CREAT 和 O_EXCL的用法区别: 1)首先我们还是来看一下O_CREATd的原注解:
代码语言:javascript复制 O_CREAT
If pathname does not exist, create it as a regular file.
这里表明当我们打开一个不存在的文件时,在使用open函数里面形参flag为O_CREAT,它就会自动创建这个不存在的文件。例如下面,我在day目录下打开一个不存在的文件b.txt,然后通过这个O_CREAT就会在day目录下创建这个不存在的文件:
代码语言:javascript复制#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd = -1; // fd 就是file descriptor,文件描述符
char buf[100] = {0};
char writebuf[20] = "hhhhohohohoh";
int ret = -1;
// 第一步:打开文件
fd = open("b.txt", O_RDWR | O_APPEND|O_CREAT );
if (-1 == fd) // 有时候也写成: (fd < 0)
{
printf("文件打开错误n");
// return -1;
_exit(-1);
}
else
{
printf("文件打开成功,fd = %d.n", fd);
}
// 第二步:读写文件
// 写文件
ret = write(fd, writebuf, strlen(writebuf));
if (ret < 0)
{
printf("write失败.n");
_exit(-1);
}
else
{
printf("write成功,写入了%d个字符n", ret);
}
close(fd);
_exit(0);
}
演示效果:
注意:open中加入O_CREAT后,不管原来这个文件存在与否都能打开成功,如果原来这个文件不存在则创建一个空的新文件,如果原来这个文件存在则会重新创建这个文件,原来的内容会被消除掉(这个有点类似于先删除原来的文件再创建一个新的)。 2)O_EXCL的源码注释如下:
代码语言:javascript复制 O_EXCL Ensure that this call creates the file: if
this flag is specified in conjunction with
O_CREAT, and pathname already exists, then
open() fails with the error EEXIST.
When these two flags are specified, sym‐
bolic links are not followed: if pathname
is a symbolic link, then open() fails
regardless of where the symbolic link
points.
In general, the behavior of O_EXCL is unde‐
fined if it is used without O_CREAT. There
is one exception: on Linux 2.6 and later,
O_EXCL can be used without O_CREAT if path‐
name refers to a block device. If the
block device is in use by the system (e.g.,
mounted), open() fails with the error
EBUSY.
On NFS, O_EXCL is supported only when using
NFSv3 or later on kernel 2.6 or later. In
NFS environments where O_EXCL support is
not provided, programs that rely on it for
performing locking tasks will contain a
race condition. Portable programs that
want to perform atomic file locking using a
lockfile, and need to avoid reliance on NFS
support for O_EXCL, can create a unique
file on the same filesystem (e.g., incorpo‐
rating hostname and PID), and use link(2)
to make a link to the lockfile. If link(2)
returns 0, the lock is successful. Other‐
wise, use stat(2) on the unique file to
check if its link count has increased to 2,
in which case the lock is also successful.
这里大概是讲了:在linux内核2.6版本以及后面的版本可以单独使用O_EXCL对块设备来说的话,一般的话O_EXCL和O_CREAT是要结合一起来用的(这样做的目的是当我们去创建一个新的文件,如果我们不小心在写代码输入还是之前已经存在的文件,同时使用O_EXCL和O_CREAT作为参数传入到open函数中去做为形参,这样可以给我们一个报错提醒,就知道没有创建一个新文件成功)。这里我创建一个已经存在的b.txt本文文件,然后另外一个代码是创建一个不存在的c.txt文本文件:
代码语言:javascript复制#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd = -1; // fd 就是file descriptor,文件描述符
char buf[100] = {0};
char writebuf[20] = "hhhhohohohoh";
int ret = -1;
// 第一步:打开文件
fd = open("a.txt", O_RDWR | O_TRUNC|O_APPEND );
if (-1 == fd) // 有时候也写成: (fd < 0)
{
printf("文件打开错误n");
// return -1;
_exit(-1);
}
else
{
printf("文件打开成功,fd = %d.n", fd);
}
// 第二步:读写文件
// 写文件
ret = write(fd, writebuf, strlen(writebuf));
if (ret < 0)
{
printf("write失败.n");
_exit(-1);
}
else
{
printf("write成功,写入了%d个字符n", ret);
}
close(fd);
_exit(0);
}
43
44#include <stdio.h>
45#include <sys/types.h>
46#include <sys/stat.h>
47#include <fcntl.h>
48#include <unistd.h>
49#include <string.h>
50 int main(int argc, char *argv[])
51{
52
53 int fd = -1; // fd 就是file descriptor,文件描述符
54 char buf[100] = {0};
55 char writebuf[20] = "hhhhohohohoh";
56 int ret = -1;
57 // 第一步:打开文件
58 fd = open("c.txt", O_RDWR | O_TRUNC|O_APPEND );
59 if (-1 == fd) // 有时候也写成: (fd < 0)
60 {
61 printf("文件打开错误n");
62 // return -1;
63 _exit(-1);
64 }
65 else
66 {
67 printf("文件打开成功,fd = %d.n", fd);
68
69 }
70 // 第二步:读写文件
71 // 写文件
72 ret = write(fd, writebuf, strlen(writebuf));
73 if (ret < 0)
74 {
75 printf("write失败.n");
76 _exit(-1);
77 }
78 else
79 {
80 printf("write成功,写入了%d个字符n", ret);
81 }
82 close(fd);
83 _exit(0);
84}
第一个代码演示效果:
第二个代码演示效果:
二、O_NONBLOCK和O_SYNC的使用: 1)先来看O_NOBLOCK的原注释:
代码语言:javascript复制 O_NONBLOCK or O_NDELAY
When possible, the file is opened in nonblocking mode. Neither
the open() nor any subsequent operations on the file descriptor
which is returned will cause the calling process to wait.
Note that this flag has no effect for regular files and block
devices; that is, I/O operations will (briefly) block when
device activity is required, regardless of whether O_NONBLOCK
is set. Since O_NONBLOCK semantics might eventually be imple‐
mented, applications should not depend upon blocking behavior
when specifying this flag for regular files and block devices.
For the handling of FIFOs (named pipes), see also fifo(7). For
a discussion of the effect of O_NONBLOCK in conjunction with
mandatory file locks and with file leases, see fcntl(2).
这里的话主要讲的是对文件操作的阻塞式和非阻塞式:如果一个函数时阻塞式的,则我们调用这个函数时当前进程有可能被卡住,阻塞住,实质是这个函数内部要完成的事情条件不具备,当前没法做,要等待条件成熟函数被阻塞助理就不能立刻返回,如果一个函数时非阻塞式的,那么我们调用这个函数后一定会立即返回,但是函数有没有完成任务不一定;我们打开一个文件,默认情况下是阻塞式的,如果你希望以非阻塞的方式打开文件,则flag中的要加O_NONBLOCK标志,这里我试验了一下,没啥明显效果(下次有新发现,再进行完善改进,我就不用代码做演示了)。 2)还是先看O_SYNC的原注释:
代码语言:javascript复制 O_SYNC Write operations on the file will complete
according to the
requirements of synchronized I/O file
integrity completion (by
contrast with the synchronized I/O data integrity completion
provided by O_DSYNC.)
By the time write(2) (or similar) returns, the output data and
associated file metadata have been transferred to the underly‐
ing hardware (i.e., as though each write(2) was followed by a
call to fsync(2)). See NOTES below.
这里的话主要讲的是: 1)write阻塞等待底层完成写入后才返回到应用层 2)无O_SYNC时write只是将内容写入到底层缓冲区即可返回,然后底层(操作系统中负责实现open、write这些操作的那些代码也包含OS中读写硬盘等底层硬件的代码),在合适的时候会将buf中的内容一次性的同步到硬盘中。这种设计是为了提升硬件操作的性能和销量提升硬件寿命;但是有时候我们希望硬件不要等待,直接将我们的内容写入到硬盘中,这时候就可以用O_SYNC标志(这个实验后,也看不到明显的效果,我也不用代码演示了,大家要明白这里的原理即可)。 三、总结: 通过这两天的写文章学习,让我对open函数的用法理解更深了,以后遇到陌生函数,可以用man手册来查看它的用法就可以了,做到举一反三,活学活用。