引言:

Unix系统中主要的文件操作包括:

  • open
  • read
  • write
  • lseek
  • close

unbuffered IO和standard I/O相对应,后面的章节我们会讨论这两者的区别。

在讨论open函数的时候,会引入原子操作,多进程通信(共享文件描述符)和内核相关的数据结构。

一,文件描述符

对应内核来说,每一个打开的文件都对应一个非负整数。

有三个特殊的文件描述符:

  • 0表示标准输入
  • 1表示标准输出
  • 2表示标准错误输出

对于较新的内核来说(Linux3.2.0,Solaris10等),文件描述符的数量并没有明确的限制,受限于内存的大小。

二,常用的几个文件操作函数

常用的文件操作函数包括:open,read,write,lseek,close

1 open和openat函数

函数声明:

#include <fcntl.h>
int open (const char *path, int oflag, … /* mode_t mode */);
int openat (int fd, const char *path, int oflag, … /* mode_t mode */);

返回值:

OK:文件描述符(非负整数)

Error:-1

注:参数列表中,“...”表示不同的系统和标准中,该处的参数可能不相同。

参数说明:

path:文件名

oflag:打开创建文件的属性。

下面有五个必选的oflag参数值,这五个值有切只能选一个。另外还有若干个可选参数值,可以自行百度。

细节说明:

由open和openat返回的文件描述符保证为未使用的最小的文件描述。有的应用利用这一特性,先关闭标准输入描述符0,就可以在标准输入描述0上打开文件。

参数fd可以区分open和openat函数。其取值有三种可能:

  1. path表示一个绝对路径,则fd参数无用,openat的功能和open相同;
  2. path表示一个相对路径,则fd是一个文件描述符,指定了path在文件系统中的起始位置,fd为打开path父目录时获取的文件描述符;
  3. path表示一个相对路径,而fd的值为AT_FDCWD,这时,path的父目录为当前工作目录,openat和open的功能相同。

openat函数解决了两个问题:

  • 在多线程条件下,默认各个线程的工作目录时相同的(当前工作目录),使用这个函数可以使得各个线程的指定不同的工作目录;
  • 提供了一种方法解决TOCTTOU(time-of-check-to-time-of-use) error。

这里介绍一下TOCTTOU错误。该类错误指的是,程序是非常脆弱的(vulnerable)如果该程序调用了两个文件相关的函数,第二个函数依赖于第一个函数的结果。因为两个函数是非原子操作,被操作的文件可能被两个函数轮流操作(线程切换),导致第一个函数的结果出错,从而程序出错。

2 creat函数

函数声明:

#include <fcntl.h>

int creat(const char* path, mode_t mode);

返回值:

  • OK:文件描述符(只写)
  • Error:-1

creat函数相当于下面这样调用open函数

open (path, O_WEONLY | O_CREAT | O_TRUNC, mode);

creat有一点不方便,因为它打开的文件描述符是只读的,如果希望写入之后读回,需要依次调用creat、close和open,才能实现。

因此,在这种场景下,一个更好的打开文件的方法是像下面这样调用open函数:

open (path, O_RDWR | O_CREAT | O_TRUNC, mode);

3 close函数

函数声明:

#include <unistd.h>

int close(int fd);

返回值:

  • 0 :OK
  • -1:Error

关闭一个文件会释放所有当前进程加在该文件上的记录锁。

4 lseek函数

每一个打开的文件都有一个”当前文件偏移量(current file offset)“,该偏移量是一个非负整数,记录了从文件开始到当前位置的字节数。

函数声明:

#include <unistd.h>

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

参数说明:

offset的作用取决于参数whence的值:

  • 如果whence的值是SEEK_SET,文件的偏移量设置为offset个字节;
  • 如果whence的值是SEEK_CUR,文件的偏移量设置为当前偏移量加上参数offset的值;
  • 如果whence的值是SEEK_END,文件的偏移量设置为文件长度加上参数offset的值,offset可以是正值或负值。

细节说明:

获取当前文件偏移量的方法:

 off_t currpos;

 currpos = lseek(fd, , SEEK_CUR);

lseek只记录当前文件在内核中的偏移量,并不会引起任何的IO操作。返回的offset将会在后面的read或write函数中使用。

偏移量可以比当前文件的长度大,这时,再调用write函数时,将扩展该文件的长度。这样的操作相当于在文件中建了一个洞,该洞范围内读时返回0。

使用od命令可以看到文件中的hole

4 read函数

函数声明:

#include <unistd.h>

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

返回值:

  • 正整数:读入的字节数
  • 0:文件结尾
  • -1: error

细节说明:

在一些情况下,函数返回的字节数比指定的读入字节数要小,多数是因为读到了文件末尾,或者指定的读取位置中包含的字节数小于指定的读入字节数,这时,read返回的为可读到的字节数。

5 write函数

函数声明:

#include <unistd.h>

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

返回值:

  • 非负整数:写入的字节数,OK
  • -1: Error

返回值总是等于参数nbytes的值,否则就会报错。

对于常规的文件来说,写操作总是从当前文件偏移量开始。

三、小结

简单地介绍了一下常用的文件IO操作,并介绍了一些使用上的细节,比较常规。

下一篇讲介绍更多文件IO的特性,包括:dup,fcntl,sync,fsync和ioctl函数。。

好久没写博客了,又第一次用mac下的一个博客软件写,不太熟悉,所以写的比较简单,以后会写的更努力。

参考资料:

《Advanced Programming in the UNIX Envinronment 3rd》

UNIX高级环境编程(1)File I/O的更多相关文章

  1. UNIX高级环境编程1

    UNIX高级环境编程1 故宫角楼是很多摄影爱好者常去的地方,夕阳余辉下的故宫角楼平静而安详. 首先,了解一下进程的基本概念,进程在内存中布局和内容. 此外,还需要知道运行时是如何为动态数据结构(如链表 ...

  2. UNIX高级环境编程(14)文件IO - O_DIRECT和O_SYNC详解 < 海棠花溪 >

    春天来了,除了工作学习,大家也要注意锻炼身体,多出去运动运动.  上周末在元大都遗址公园海棠花溪拍的海棠花.   进入正题. O_DIRECT和O_SYNC是系统调用open的flag参数.通过指定o ...

  3. Unix高级环境编程

    [07] Unix进程环境==================================1. 进程终止    atexit()函数注册终止处理程序.    exit()或return语句:    ...

  4. UNIX高级环境编程(2)FIle I/O - 原子操作、共享文件描述符和I/O控制函数

    引言: 本篇通过对open函数的讨论,引入原子操作,多进程通信(共享文件描述符)和内核相关的数据结构. 还会讨论集中常见的文件IO控制函数,包括: dup和dup2 sync,fsync和fdatas ...

  5. UNIX高级环境编程(10)进程控制(Process Control)- 竞态条件,exec函数,解释器文件和system函数

    本篇主要介绍一下几个内容: 竞态条件(race condition) exec系函数 解释器文件    1 竞态条件(Race Condition) 竞态条件:当多个进程共同操作一个数据,并且结果依赖 ...

  6. UNIX高级环境编程(9)进程控制(Process Control)- fork,vfork,僵尸进程,wait和waitpid

    本章包含内容有: 创建新进程 程序执行(program execution) 进程终止(process termination) 进程的各种ID   1 进程标识符(Process Identifie ...

  7. UNIX高级环境编程(4)Files And Directories - umask、chmod、文件系统组织结构和链接

    本篇主要介绍文件和文件系统中常用的一些函数,文件系统的组织结构和硬链接.符号链接. 通过对这些知识的了解,可以对Linux文件系统有更为全面的了解.   1 umask函数 之前我们已经了解了每个文件 ...

  8. UNIX高级环境编程(3)Files And Directories - stat函数,文件类型,和各种ID

    在前面的两篇,我们了解了IO操作的一些基本操作函数,包括open.read和write. 在本篇我们来学习一下文件系统的其他特性和一个文件的属性,涉及的函数功能包括: 查看文件的所有属性: 改变文件所 ...

  9. UNIX高级环境编程(16)文件系统 < 雨后 >

    来点绿色放松一下眼睛吧 :) 文件系统是对文件和目录的组织集合. 一 设备文件 设备文件和系统的某个设备相对应. 设备驱动程序 处理设备的所有IO请求. 提供了一致的API接口,对应于系统调用的ope ...

随机推荐

  1. C++中虚函数的动态绑定和多态性

    目录 静态类型 vs 动态类型.静态绑定 vs 动态绑定 虚函数动态绑定实现机制.虚析构函数 多态性 一.静态 vs 动态 静态类型 VS 动态类型.静态类型指的是对象声明的类型,在编译器确定的.动态 ...

  2. Zookeeper初见

    这是Zookeeper学习总结 的系列文章. ZK简介 ZK部署及运行 ZK的常用API 创建会话 创建节点 删除节点 读取数据节点 更新数据 检测节点是否存在 ZK的开源封装

  3. (转) Java我的高效编程之环境搭建

    前言:刚毕业, 工作之余写博客有利于提高技术,更是能帮助人,接下来会认认真真写好每一篇博客.希望大家多多支持.废话不多说,马上开始.这是一篇环境搭建的博客. jdk+eclipse+svn+maven ...

  4. 下拉加载dropload.js

    使用下拉加载 使用需要引用的css <link rel="stylesheet" href="../dist/dropload.css"> 使用需要 ...

  5. Beta阶段——Scrum 冲刺博客第一天

    一.当天站立式会议照片一张 二.每个人的工作 (有work item 的ID),并将其记录在码云项目管理中 昨天已完成的工作 今日是Beta冲刺第一天,昨日没有完成的工作 今天计划完成的工作 实现对i ...

  6. H5开发中遇到的问题及解决办法

    记不得什么时候进行H5开发的学习了,只知道是从2016年8月1日开始修复Bug,计划每天把学到的东西以及遇到问题时候的解决方案都记录下来,希望自己能够坚持下去,每天积累一点,希望有所进步吧. 1.Th ...

  7. Tomcat 配置上传文件到项目外的路径

    使用 Tomcat 作为服务器的时候,将上传文件保存在项目路径下,每次重启服务或者打成 war 包的时候很容易丢失上传的文件,于是我们配置 Tomcat 把文件保存到项目外的其他磁盘路径: 1. 打开 ...

  8. 常用算法3 - 字符串查找/模式匹配算法(BF & KMP算法)

    相信我们都有在linux下查找文本内容的经历,比如当我们使用vim查找文本文件中的某个字或者某段话时,Linux很快做出反应并给出相应结果,特别方便快捷! 那么,我们有木有想过linux是如何在浩如烟 ...

  9. [转] Linux Daemon Writing HOWTO

    Linux Daemon Writing HOWTO Devin Watson v1.0, May 2004 This document shows how to write a daemon in ...

  10. python分布式爬虫打造搜索引擎--------scrapy实现

    最近在网上学习一门关于scrapy爬虫的课程,觉得还不错,以下是目录还在更新中,我觉得有必要好好的做下笔记,研究研究. 第1章 课程介绍 1-1 python分布式爬虫打造搜索引擎简介 07:23 第 ...