一、引言

  UNIX系统中的大多数文件对I/O只需用到5个函数:open/read/write/lseek和close,这些函数都是不带缓冲I/O(Unbuffered I/O)。只要涉及到多个进程间共享资源,原子操作的概念就变得非常重要,后面将介绍:dup/fcntl/sync/fsync和ioctl。

二、文件描述符

  对于内核而言,多有打开的文件都通过文件描述符引用。文件描述符是一个非负整数,当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。按照惯例:UNIX系统shell把文件描述符0(STDIN_FILENO)与进程的标准输入关联,文件描述符1(STDOUT_FILENO)与标准输出关联,文件描述符2(FILEERR_FILENO)与标准错误关联,这几个宏定义在<unistd.h>中。

三、函数open和openat

#include <fcntl.h>
int open(const char *path, int aflag,.../*mode_t mode*/);
int openat(int fd, char *path, int aflag, .../*mode_t mode*/)
//若成功,返回文件描述符;若出错,返回-1

  ISO C用...这种方法表明余下的参数数量极其类型是可变的,并且由open/openat函数返回的文件描述符一定是最小的未用描述符数值。对于open函数而言,仅当创建新文件时才使用最后这个参数。path参数是要打开或创建文件的名字,aflag参数可用来说明此函数的多个选项。aflag参数由两类组成:

第一类,必须要在5个中指定一个且只能指定一个:O_RDONLY (只读打开)、O_RDONLY (只写打开)、O_RDWR(读/写打开)、O_EXEC(只执行打开)、O_SERACH (应用于目录,搜索打开)

第二类,可以叠加:O_APPEND(每次写时追加都文件的尾端)、O_CREATE(若此文件不存在则创建它,并且此时需要指定mode来设置新文件访问权限)、O_EXCL(如果同时指定了O_CREATE,当文件存在时,则出错)、O_DIRECTORY(如果path引用的不是目录,则出错)、O_NONBLOCK(如果path引用的是一个FIFO等,此选项为文件的本次打开操作和后续I/O设置为非阻塞式)、O_SYNC(使每次write等待物理I/O操作完成,包括由该write操作引起的文件属性更新所需的I/O)、O_TRUNC(若此文件存在,将其截断为0)、O_DSYNC(使每次write要等待物理I/O操作完成,但是如果该写操作并不影响读取刚写入的数据,则不需等待文件属性被更新)、O_RSYNC(使每一个以文件描述符作为参数进行的read操作等待,直至所有对文件同一部分挂起的写操作完成)

  fd参数把open和openat函数区分开:

1.path参数指定的是绝对路径名,这种情况下,fd参数被忽略,openat函数就相当于open函数

2.path参数指定的是相对路径名,fd参数指出了相对路径名在文件系统中的开始位置。fd参数是通过打开相对路径名所在的目录来获取

3.path参数指定的是相对路径名,fd参数具有特殊值AT_FDCW,路径名在当前工作目录中获取,openat函数在操作上与open函数类似。

  openat函数存在的意思有两点:1.让线程可以使用相对路径名打开目录中的文件,而不再只能打开当前工作目录;2.可以避免time-of-check-to-time-of-use错误。

四、函数create和函数close

  open函数提供了O_CREAT和O_TRUNC,于是就不再需要单独的create函数。

  当一个进程结束时,内核自动关闭它所有的打开文件,很多程序都利用了这一功能而不显式调用close关闭打开文件。

五、函数lseek

  每个打开文件都有一个预期相关联的“当前文件偏移量”(current file offset),它通常是一个非负整数,用以度量从文件开始处计算的字节数。通常读写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数。按系统默认的抢矿,当打开一个文件时,除非指定O_APPEND选项,否则该偏移量被设置为0。我们可以调用lseek显式地为一个打开文件设置偏移量。

#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
//若成功,返回新的文件偏移量;若出错,返回-1

  对参数offset的解释与参数whence的值相关:

1.SEEK_SET  :则将该文件的偏移量设置为据文件开始处offset个字节

2.SEEK_CUR :则将该文件的偏移量设置为当前值加offset(offset可以为负数)

3.SEEK_END :则将该文件的偏移量设置为文件长度加offset(offset可以为负数)

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> int main()
{
if(lseek(STDIN_FILENO, , SEEK_CUR) == -)
{
printf("cannot seek\n");
}
else
{
printf("seek ok \n");
}
exit();
}

3-1:测试标准输入能否被设置偏移量

  因为某些设备也可能允许负的偏移量。但对于普通文件,其偏移量必须是非负值。因为其返回值可能是负值,所以在比较lseek的返回值时应当谨慎,不要测试它是否小于0,而要测试它是否等于-1.还有一点需要注意的是:lseek仅将当前的偏移量记录在内核中,它并不引起任何I/O操作,然后,该偏移量用于下一个读写操作。

#include <apue.h>
#include <fcntl.h> char buf1[] = "abcdefghij";
char buf2[] = "ABCDEFGHIJ"; int main()
{
int fd;
if((fd = creat("file.txt", FILE_MODE)) < )
{
printf("create error\n");
return -;
} if(write(fd, buf1, ) != )
{
printf("buf1 write error\n");
return -;
} if(lseek(fd, , SEEK_SET) == -)
{
printf("lseek error\n");
return -;
} if(write(fd, buf2, ) != )
{
printf("buf2 write error");
return -;
} return ;
}

3-2:创建一个具有空洞的文件

六、函数read

  调用read函数从打开文件中读数

#include <unistd.h>
size_t read(int fd, void *buf, size_t nbytes);
//返回值:读到的字节数,若已到文件尾,返回0,;若出错,返回-1

  有多种情况可使实际独到的字节数少于要求读的字节数:

1.读普通文件时,在读到要求字节数之前到达文件尾端

2.从终端设备读时,通常一次最多读一行

3.当从网络设备读时,网络中的缓冲机制可能造成返回值小于所要求读的字节数

4.当从管道或FIFO读时,若管道包含的字节少于所需的数量,那么read将只返回实际可用的字节数

5.当从某些面向记录的设备读时,一次最多返回一个记录

6.当一信号造成中断,而已经读了部分数据量时

APUE(3)---文件I/O (1)的更多相关文章

  1. (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  2. (三) 一起学 Unix 环境高级编程 (APUE) 之 文件和目录

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  3. apue.h文件找不到的解决办法

    参考:http://blog.csdn.net/nihaotoyou/article/details/16827675 1.首先到该书的官网下载源代码:http://www.apuebook.com/ ...

  4. 【APUE】文件I/O

    Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file descri ...

  5. [apue] 使用文件记录锁无法实现父子进程交互执行同步

    父子进程间交互执行是指用一种同步原语,实现父进程和子进程在某一时刻只有一个进程执行,之后由另外一个进程执行,用一段代码举例如下: SYNC_INIT(); , counter=; pid_t pid ...

  6. [apue] linux 文件访问权限那些事儿

    前言 说到 linux 上的文件权限,其实我们在说两个实体,一是文件,二是进程.一个进程能不能访问一个文件,其实由三部分内容决定: 文件的所有者.所在的组: 文件对所有者.组用户.其它用户设置的权限访 ...

  7. [11]APUE:(文件)记录锁

    [a] 概念 建议锁:在遵循相同记录锁规则的进程间生效,通常用于保证某个程序自身多个进程间的数据一致性 强制锁:意在保证所有进程间的数据一致性,但不一定有效:如不能应对先 unlink 后建立同名副本 ...

  8. [04]APUE:文件与目录

    [a] stat / lstat / fstat #include <sys/stat.h> int stat(const char *restrict pathname, struct ...

  9. [03]APUE:文件 I/O

    [a] open #include <fcntl.h> int open(const char *path, int oflag, ... ,mode_t mode) 成功返回文件描术符, ...

  10. 重读APUE(5)-文件权限

    文件,目录,权限 1. 用名称打开任一个类型的文件时,对该名字中包含的每一个目录,包括它可能隐含的当前工作目录都应该具有执行权限:这就是目录执行权限通常被称为搜索位的原因: 例如:为了打开文件/usr ...

随机推荐

  1. C语言中的printf函数的输入输出问题

    这个问题是个很基础,但是我一直不知道的问题,是同学问了之后才知道的,长知识了. 这里要注意的是,printf函数是从右向左计算,从左向右输出. 距离如下: #include <stdio.h&g ...

  2. C 游戏所要看的书

    C 游戏所要看的书 1.C++primer中文版第4版     经典啊2.C++标准程序库自修教程与参考手册 3.Windows程序设计第5版 4.MFC windows程序设计第2版中文版 5.VC ...

  3. 分布式缓存系统 Memcached 状态机之socket连接与派发

    上节已经分析到了主线程中监听socket注册事件和工作线程中连接socket注册事件的回调函数都是event_handler,且event_handler的核心部分都是一个有限状态机:drive_ma ...

  4. PHP传入数组到js

    1.方式一,处理成字符串 js再将字符串处理成数组. var spec1_default = "{$spec1_default}"; spec1_default = spec1_d ...

  5. 第六章 深入分析ClassLoader工作机制

    补充(非书中): Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件).类加载器负责读取Java字节代码,并转换成 java.lan ...

  6. C#中Monitor对象与Lock关键字的区别分析

    这篇文章主要介绍了C#中Monitor对象与Lock关键字的区别,需要的朋友可以参考下 Monitor对象 1.Monitor.Enter(object)方法是获取 锁,Monitor.Exit(ob ...

  7. python's seventh day for me set

    数据类型的补充: 对于元祖:  如果只有一个元素,并且没有逗号,此元素是什么数据类型,该表达式就是什么数据类型. tu = ('顾清秋') tul = ('顾清秋',) print(type(tu)) ...

  8. 分布式爬虫搭建系列 之三---scrapy框架初用

    第一,scrapy框架的安装 通过命令提示符进行安装(如果没有安装的话) pip install Scrapy 如果需要卸载的话使用命令为: pip uninstall Scrapy 第二,scrap ...

  9. STM32使用无源蜂鸣器演奏歌曲

    上一次使用了有源蜂鸣器,只能发出固定的”滴滴“声,当然不能满足于此呀.使用无源蜂鸣器,只要输出不同频率的PWM波,即可发出不同的音符. 不同的音符组合起来就是一个曲子了. 改变PWM的音调,可以输出D ...

  10. MAPREDUCE的原理和使用

    简介: Mapreduce是一个分布式运算程序的编程框架,是用户开发“基于hadoop的数据分析应用”的核心框架: Mapreduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分 ...