Linux环境下的open函数分析(二)

2022-03-18 15:22:56 浏览数 (1)

-----哈哈哈,小伙伴们,今天的分享是接着昨天的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手册来查看它的用法就可以了,做到举一反三,活学活用。

0 人点赞