Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1011896
  • 博文数量: 135
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1785
  • 用 户 组: 普通用户
  • 注册时间: 2016-12-21 22:26
个人简介

90后空巢老码农

文章分类

全部博文(135)

文章存档

2020年(33)

2019年(54)

2018年(47)

2017年(1)

我的朋友

分类: LINUX

2019-12-29 22:32:50

原子操作是许多系统调用得以正确执行的必要条件



文件控制操作:fcntl()


点击(此处)折叠或打开

  1. #include <fcntl.h>
  2. int fcntl(int fd, int cmd, ...);
  3. /*return on success depends on cmd, or -1 on error*/
打开文件的状态标志:

点击(此处)折叠或打开

  1. int flags, accessMode;
  2. flags = fcntl(fd, F_GETFL);
  3. if(flags == -1)
  4.     errExit("fcntl");
  5. if(flags & O_SYNC)
  6.     printf("writes are synchronized\n");

判断文件的访问模式有一点复杂,这是因为O_RDONLY(0), O_WRONLY(1), O_RDWR(2)这三个常量并不与打开文件状态标志中的单个比特位对应。因此,要判定访问模式,需要使用掩码O_ACCMODE与flag相与,将结果与三个常量进行对比

点击(此处)折叠或打开

  1. accessMode = flag&O_ACCMODE;
  2. if (accessMode == O_WRONLY || accessMode == O_RDWR)
  3.     printf("file is writable\n");
F_SETFL命令可以修改某些状态标志。允许更改的标志有:O_APPEND, O_NONBLOCK, O_NOATIME, O_ASYNC, O_DIRECT

文件描述符和打开文件之间的关系

由于目前Chinaunix上传图片老是失败,只能转为文字描述,待上传图片功能修正之后,这边会上传。
针对文件,有三个结构是我们必须要记录在脑子里的,这三个结构可以理解为通过两个mapping阶段相互串联在一起的

第一个结构就是每个进程都有一个文件描述符表,它是一个数组,下标表示其文件描述符,内容包含文件描述符标志(当前只有close-on-exec)和一个文件指针;这个指针指向的就是第二个结构,也可以把指针指向这个动作称为第一个mapping

第二个结构就是操作系统为每个打开的文件维护了一个系统级的打开文件表,里面记录了关于某个打开文件的文件偏移量、状态标志等信息,最后是一个文件指针,指向第三个结构,也可以吧这个指针的指向这个动作称为第二个mapping

第三个结构就是一个系统级的i-node表,记录了文件的元信息


复制文件描述符

复制文件描述符是针对第一个结构到第二个结构之间的map做了一次调整,主要有一下三个函数

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. int dup(int oldfd);
  3. /*returns (new) file descriptor on success, or -1 on error*/
  4. #include <unistd.h>
  5. int dup2(int oldfd, int newfd);
  6. /*returns (new) file descriptor on success, or -1 on error*/
  7. #define _GNU_SOURCE
  8. #include <unistd.h>
  9. int dup3(int oldfd, int newfd, int flags);
  10. /*returns (new) file descriptor on success, or -1 on error*/

其中dup2和dup3均指定了新文件描述符fd,dup3比dup2多了一个flags参数(就是之前说过的close-on-exec标志)
以上操作均可以由fcntl()来完成,使用大于等于startfd的最小值来返回newfd

点击(此处)折叠或打开

  1. newfd = fcntl(oldfd, F_DUPFD[|F_DUPFD_CLOEXEC], startfd);



在文件特定偏移量处的I/O:pread()和pwrite(), 原子操作

这两个系统调用会完成与read()和write()相类似的工作,只是前两正会在offset参数所指定的位置进行文件I/O操作,而非始于文件当前偏移量处,且它们不会改变文件的当前偏移量

点击(此处)折叠或打开

  1. #include <unistd.h>
  2. ssize_t pread(int fd, void *buf, size_t count, off_t offset);
  3. /*returns number of bytes read, 0 on EOF, or -1 on error*/
  4. ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
  5. /*returns number of bytes written, or -1 on error*/
对于这两个函数而言,文件描述符所指定的文件必须是可定位的(允许lseek()操作),多用于多线程编程。




scatter-gather  I/O,readv()和writev(),原子操作


点击(此处)折叠或打开

  1. #include <sys/uio.h>
  2. struct iovec{
  3.     void *iov_base;
  4.     size_t iov_len;
  5. };
  6. ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
  7. /*returns number of bytes read, 0 on EOF, or -1 on error*/
  8. ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
  9. /*returns number of bytes written, or -1 on error*/




截断文件


点击(此处)折叠或打开

  1. #include <unistd.h>
  2. int truncate(const char *pathname, off_t length);
  3. int ftruncate(int fd, off_t length);
  4. /*both return 0 on success, or -1 on error*/

将文件大小设置为length,若文件长度大于参数length,丢弃超出部分;若小于length,在文件尾部添加一系列空字节或是一个文件空洞

非阻塞I/O

在打开文件时指定O_NONBLOCK标志,目的有二:
1. 若open()未能立即打开文件,返回错误,而非陷入阻塞
2. 调用open()成功之后,后续的i/o操作也是非阻塞的


大文件I/O

要想获取LFS功能,推荐的做法是:在编译程序时,将宏_FILE_OFFSET_BITS的值定义为64,如

点击(此处)折叠或打开

  1. $ cc -D_FILE_OFFSET_BITS=64 prog.c
另一种方法是在C语言的源文件中,在包含所有头文件之前添加如下宏定义,这样,所有相关的32位函数和数据类型将自动转换为64位版本

点击(此处)折叠或打开

  1. #define _FILE_OFFSET_BITS 64

这样,在打印off_t类型的时候,需要将其强制转换为long long类型

点击(此处)折叠或打开

  1. printf("offset=%lld\n", (long long) offset)

/dev/fd目录

对于每一个进程,内核都提供有一个特殊的虚拟目录/dev/fd。该目录中包含/dev/fd/n形式的文件名,其中n是与进程中的打开文件描述符相对应的编号,打开/dev/fd目录中的一个文件等同于复制相应的文件描述符,所以,如下两行代码是等价的

点击(此处)折叠或打开

  1. fd = open("/dev/fd/1", O_WRONLY);
  2. fd = dup(1);

创建临时文件


点击(此处)折叠或打开

  1. #include <stdlib.h>
  2. int mkstemp(char *template);
  3. /*returns file descriptor if OK, -1 on error*/

基于调用者提供的末班,mkstemp()函数生成一个唯一文件名并打开该文件,返回一个可用于I/O调用的文件描述符,该模板参数采用路径名形式,其中最后6个字符必须为xxxxxx,这6个字符将被替换,以保证文件名的唯一性,且秀干后的参数将通过template参数传回去。
文件拥有者对mkstemp()函数建立的文件拥有读写权限(其他用户没有任何操作权限),且打开文件时使用了O_EXCL标志,以保证调用者以独占的方式访问文件

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. char *tmpnam(char *ptr);
  3. /*returns: pointer to unique pathname*/
  4. FILE *tmpfile(void);
  5. /*returns file pointer on success, or NULL on error*/
tmpfile()会创建一个名称唯一的临时文件,并以读写方式将其打开(也有O_EXCL标志),文件流关闭后将自动删除临时文件

阅读(144) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~