open函数

 int open(const char *pathname, int flags, mode_t mode);

参数说明:

(1)pathname: 表示要打开的文件路径

(2)flags: 用于指示打开文件的选项,常用的有O_RDONLY、 O_WRONLY和O_RDWR,还有一些选项如下:

  • O_APPEND: 每次进行写操作时, 内核都会先定位到文件尾, 再执行写操作
  • O_ASYNC: 使用异步I/O模式
  • O_CLOEXEC: 在打开文件的时候, 就为文件描述符设置FD_CLOEXEC标志。 这是一个新的选项, 用于解决在多线程下fork与用fcntl设置FD_CLOEXEC的竞争问题。 某些应用使用fork来执行第三方的业务, 为了避免泄露已打开文件的内容, 那些文件会设置FD_CLOEXEC标志。 但是fork与fcntl是两次调用, 在多线程下, 可能会在fcntl调用前, 就已经fork出子进程了, 从而导致该文件句柄暴露给子进程
  • O_CREAT: 当文件不存在时, 就创建文件
  • O_DIRECT: 对该文件进行直接I/O, 不使用VFS Cache
  • O_DIRECTORY: 要求打开的路径必须是目录
  • O_EXCL: 该标志用于确保是此次调用创建的文件, 需要与O_CREAT同时使用; 当文件已经存在时, open函数会返回失败
  • O_LARGEFILE: 表明文件为大文件
  • O_NOATIME: 读取文件时, 不更新文件最后的访问时间
  • O_NONBLOCK、 O_NDELAY: 将该文件描述符设置为非阻塞的( 默认都是阻塞的)
  • O_SYNC: 设置为I/O同步模式, 每次进行写操作时都会将数据同步到磁盘, 然后write才能返回
  • O_TRUNC: 在打开文件的时候, 将文件长度截断为0, 需要与O_RDWR或O_WRONLY同时使用。在写文件时, 如果是作为新文件重新写入, 一定要使用O_TRUNC标志, 否则可能会造成旧内容依然存在于文件中的错误

(3)mode: 只在创建文件时需要, 用于指定所创建文件的权限位( 还要受到umask环境变量的影响)

lseek函数

 off_t lseek(int fd, off_t offset, int whence);

该函数用于将fd的文件偏移量设置为以whence为起点, 偏移为offset的位置。 其中whence可以为三个值: SEEK_SET、 SEEK_CUR和SEEK_END, 分别表示为“文件的起始位置”、 “文件的当前位置”和“文件的末尾”, 而offset的取值正负均可。 lseek执行成功后, 会返回新的文件偏移量。文件偏移是基于某个打开文件来说的, 一般情况下, 读写操作都会从当前的偏移位置开始读写( 所以read和write都没有显式地传入偏移量) , 并且在读写结束后更新偏移量。

返回值:当lseek执行成功时, 它会返回最终以文件起始位置为起点的偏移位置。 如果出错,则返回-1, 同时errno被设置为对应的错误值。也就是说, 一般情况下, 对于普通文件来说, lseek都是返回非负的整数, 但是对于某些设备文件来说, 是允许返回负的偏移量。 因此要想判断lseek是否真正出错, 必须在调用lseek前将errno重置为0,然后再调用lseek, 同时检查返回值是否为-1及errno的值。 只有当两个同时成立时, 才表明lseek真正出错了。

read函数

 ssize_t read(int fd, void *buf, size_t count);

read尝试从fd中读取count个字节到buf中, 并返回成功读取的字节数, 同时将文件偏移向前移动相同的字节数。 返回0的时候则表示已经到了“文件尾”。 read还有可能读取比count小的字节数。

使用read进行数据读取时, 要注意正确地处理错误, 也是说read返回-1时, 如果errno为EAGAIN、EWOULDBLOCK或EINTR, 一般情况下都不能将其视为错误。 因为前两者是由于当前fd为非阻塞且没有可读数据时返回的, 后者是由于read被信号中断所造成的。 这两种情况基本上都可以视为正常情况。

write函数

 ssize_t write(int fd, const void *buf, size_t count);

write尝试从buf指向的地址, 写入count个字节到文件描述符fd中, 并返回成功写入的字节数, 同时将文件偏移向前移动相同的字节数。 write有可能写入比指定count少的字节数。

dup函数

 int dup(int oldfd);
int dup2(int oldfd, int newfd);
int dup3(int oldfd, int newfd, int flags);

(1)dup:使用一个最小的未用文件描述符作为复制后的文件描述符。
(2)dup2:使用用户指定的文件描述符newfd来复制oldfd的。 如果newfd已经是打开的文件描述符, Linux会先关闭newfd, 然后再复制oldfd。
(3)dup3:只有定义了feature宏“_GNU_SOURCE”才可以使用, 它比dup2多了一个参数, 可以指定标志——不过目前仅仅支持O_CLOEXEC标志, 可在newfd上设置O_CLOEXEC标志。 定义dup3的原因与open类似, 可以在进行dup操作的同时原子地将fd设置为O_CLOEXEC, 从而避免将文件内容暴露给子进程。

在写daemon服务程序时, 基本上都有这样的流程: 首先关闭标准输出stdout、 标准出错stderr, 然后进行dup操作, 将stdout或stderr重定向。 但是在多线程程序成为主流以后,由于close和dup操作不是原子的, 这就造成了在某些情况下, 重定向会失败。 因此就引入了dup2将close和dup合为一个系统调用, 以保证原子性, 然而这依然有问题。 大家可以回顾1.2.2节中对O_CLOEXEC的介绍。 在多线程中进行fork操作时, dup2同样会有让相同的文件描述符暴露的风险, dup3也就随之诞生了。 这三个系统调用看起来有些冗余重复, 但实际上它们也是软件工程发展的结果。

sync函数

 void sync(void);
int fsync(int fd);
int fdatasync(int fd);

(1)Linux的sync是阻塞调用 ,并不是说让所有修改过的缓存进入提交队列, 并不用等待这个工作完成,这一点和APUE上面是不同的,以这个结论为准

(2)fsync只同步fd指定的文件, 并且直到同步完成才返回,它不仅同步数据, 还会同步所有被修改过的文件元数据(包括文件的访问权限、 上次访问的时间戳、 所有者、 所有组、 文件大小等信息)

(3)fdatasync与fsync类似, 但是其只同步文件的实际数据内容, 不会影响后面数据操作的元数据

sync、 fsync和fdatasync只能保证Linux内核对文件的缓冲被冲刷了, 并不能保证数据被真正写到磁盘上, 因为磁盘也有自己的缓存。

stat函数

 #include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);

(1)stat得到路径path所指定的文件基本信息
(2)fstat得到文件描述符fd指定文件的基本信息
(3)lstat与stat则基本相同, 只有当path是一个链接文件时, lstat得到的是链接文件自己本身的基本信息而不是其指向文件的信息

truncate 函数

 #include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);

(1)truncate截断的是路径path指定的文件
(2)ftruncate截断的是fd引用的文件

“截断”给人的感觉是将文件变短, 即将文件大小缩短至length长度。 实际上, length可以大于文件本身的大小, 这时文件长度将变为length的大小, 扩充的内容均被填充为0。 需要注意的是, 尽管ftruncate使用的是文件描述符, 但是其并不会更新当前文件的偏移。

PILE读书笔记_文件I/O的更多相关文章

  1. PILE读书笔记_进程环境

    进程是操作系统运行程序的一个实例, 也是操作系统分配资源的单位. 在Linux环境中, 每个进程都有独立的进程空间, 以便对不同的进程进行隔离, 使之不会互相影响. atexit函数 #include ...

  2. PILE读书笔记_标准I/O

    在学习和分析标准I/O库的同时, 可以重点与Linux的I/O系统调用进行比较. stdin. stdout和stderr都是FILE类型的文件指针, 是由C库静态定义的, 直接与文件描述符0. 1和 ...

  3. PILE读书笔记_基础知识

    程序的构成 Linux下二进制可执行程序的格式一般为ELF格式. 我们可以用readelf命令来读取二进制的信息. ELF文件的主要内容就是由各个section及symbol表组成的. 下面来分别介绍 ...

  4. 『TensorFlow』读书笔记_进阶卷积神经网络_分类cifar10_下

    数据读取部分实现 文中采用了tensorflow的从文件直接读取数据的方式,逻辑流程如下, 实现如下, # Author : Hellcat # Time : 2017/12/9 import os ...

  5. The Way to Go读书笔记_第4章_基本结构和基本数据类型

    “_”标识符 _ 本身就是一个特殊的标识符,被称为空白标识符.它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用 ...

  6. Node.js高级编程读书笔记 - 2 文件和进程处理

    Outline 3 文件.进程.流和网络 3.1 查询和读写文件 3.2 创建和控制外部进程 3.3 读写数据流 3 文件.进程.流和网络 3.1 查询和读写文件 path 从Node 0.8起,pa ...

  7. linux笔记_文件搜索命令

    一.locate命令 locate命令属于mlocate包,如果执行locate filename提示命令未找到执行安装mlocate包 # yum -y install mlocate 安装后执行l ...

  8. 『TensorFlow』读书笔记_进阶卷积神经网络_分类cifar10_上

    完整项目见:Github 完整项目中最终使用了ResNet进行分类,而卷积版本较本篇中结构为了提升训练效果也略有改动 本节主要介绍进阶的卷积神经网络设计相关,数据读入以及增强在下一节再与介绍 网络相关 ...

  9. Java精选笔记_文件上传与下载

    文件上传与下载 如何实现文件上传 在Web应用中,由于大多数文件的上传都是通过表单的形式提交给服务器的,因此,要想在程序中实现文件上传的功能,首先得创建一个用于提交上传文件的表单页面. 为了使Serv ...

随机推荐

  1. [BZOJ 1912] patrol 巡逻

    Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1912 Algorithm: K=0:res=(n-1)*2   每条边恰好走2遍 K=1 ...

  2. 1.10(java学习笔记)super关键字

    supe主要是调用父类中被重写的方法及属性. 用下列代码那说明: package cn.hcf.TestSuper; public class TestSuper { public static vo ...

  3. Problem U: 零起点学算法19——输出特殊值

    #include<stdio.h> int main() { printf("%%d"); ; }

  4. 【MySQL笔记】Excel数据导入Mysql数据库的实现方法——Navicat

    很多公司尤其有点年头的公司,财务业务部门的各种表单都是excel来做的表格,随着互联网的发展各种业务流程都电子化流程化了,再在茫茫多的文档中去查找某一个年份月份的报告是件相当枯燥的事,所以都在想办法将 ...

  5. 修改 CentOS 6.3 时区 和 时间

    1.查看当前时区和时间 date -R 2.CentOS中时区是以文件形式存在,当前时区文件位于 /etc/localtime 其他时区文件位于 /usr/share/zoneinfo下,其中中国时区 ...

  6. 破解SQLServer for Linux预览版的3.5GB内存限制 (RHEL篇) 转

    https://www.ancii.com/database/30842.html 微软发布了SQLServer for Linux,但是安装竟然需要3.5GB内存,这让大部分云主机用户都没办法尝试这 ...

  7. Linux下交叉编译gdb和gdbserver

    平台:tq2440 GCC:  gcc version 4.3.3 (Sourcery G++ Lite 2009q1-176) 这里过程中参考了下面两篇博文: http://blog.csdn.ne ...

  8. 剪切Postscript图片中的多余边框

    最近用plplot画图,其cairo ps库生成的ps图片总是不能合理地剪切掉多余的边框,于是乎自己写了一个小脚本epscrop,用修改ps图的BoundingBox. #!/bin/bash # c ...

  9. nginx和selinux冲突

    cat /var/log/audit/audit.log |grep nginx |grep denied| audit2allow -M mynginx 取出selinux中有关于nginx被拒绝的 ...

  10. ubuntu i3 xterm中文输入显示问题解决

    i3config 配置 !启动fcitx输入法管理 exec fcitx -d Xresource配置 !设置输入法管理器为fcitx xterm*inputMethod: fcitx !设置英文字体 ...