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

系统调用是如何完成一个I/O操作的呢? linux将内存分为内核区,用户区; linux内核给我们管理所有的硬件资源,应用程序通过调用系统调用和内核交互,达到使用硬件资源的目的;应用程序通过系统调用read发起一个读操作;这时候内核创建一个文件描述符,并通过驱动程序向硬件发送读指令,并将读的的数据放在这个描述符对应结构体的缓存区。但这个结构体是在内核内存区的。需要将这个数据读到用户区,这样完成了一次读操作.

读就绪:文件描述符的接收缓冲区中的数据字节数大于等于套接字接收缓冲区低水位标记的当前大小;

写就绪:该描述符发送缓冲区的可用空间字节数大于等于描述符发送缓冲区低水位标记的当前大小。

从上边的分析我们知道向内核发起一个I/O操作,要经过等待fd就绪+内核数据到用户数据区复制,完成一次I/O。

各种I/O模型比较:

1、阻塞I/O:进程被阻塞在I/O系统调用上(read、write、sendto、recvfrom等等)直到I/O条件就绪(可读/写或异常),处理后从I/O系统调用返回进程。

2、非阻塞I/O :这种方式通过指定系统调用read/write的参数为非阻塞,告知内核fd没就绪时,不阻塞进程,而是返回一个错误码,这时应该使应用进程死循环轮询,直到fd就绪

3、I/O复用( I/O 多路转接模型):在这种模型下,如果请求的 I/O 操作阻塞,则它不是真正阻塞进程,而是让其中的一个函数等待,在这期间,进程还能进行其他操作。

4、多线程阻塞I/O。把要处理的描数字分配到多个线程中,每个线程独立地调用I/O系统调用,独立处理。

5、异步I/O。通过aio_read告诉内核怎么处理,我们就不管了,内核处理完了后发个信号告诉我们,也可以用其他方式在处理完通知我们。

注:

对普通文件的读写不存在阻塞问题,对和终端、网络连接等对应的文件描述符才会阻塞

阻塞操作是指,在执行设备操作时,若不能获得资源,则进程挂起直到满足可操作的条件再进行操作。非阻塞操作的进程在不能进行设备操作时,并不挂起。被挂起的进程进入sleep状态,被从调度器的运行队列移走,直到等待的条件被满足。

同步I/O模型:第1~4 I/O模型。这5种I/O模型,说到底,I/O调用还是要用户进程自己调用,被阻塞。

异步I/O模型:第5种I/O模型。I/O调用由内核执行,进程不被阻塞。

文件描述符

对于内核而言,所有打开的文件都通过文件描述符引用。文件描述符是一个非负整数。当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。当读或写一个文件时,使用open或create返回的文件描述符标识该文件,将其作为参数传送给read或write。

按照惯例,UNIX系统shell使用文件描述符0与进程的标准输入相关联,文件描述符1与标准输出相关联,文件描述符2与标准错误输出相关联。

在依从POSIX的应用程序中,0,1,2应当替换为符号常量STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO.这些常量定义在<unistd.h>中。

open函数:打开或创建一个文件

#include <fcntl.h>

int open(const char *pathname,int oflag,...);//若成功则返回文件描述符,若出错返回-1

pathname是要打开或创建文件的名字,oflag参数用来说明此函数的多个选项

由open返回的文件描述符一定是最小的未用描述符数值

create函数:创建文件

#include <fcntl.h>

int creat(const char *pathname,mode_t mode);//若成功则返回文件描述符,若出错返回-1

mode为文件访问权限,create以只写方式打开所创建的文件

close函数

#include <unistd.h>

int close(int filedes);//若成功则返回0,若出错则返回-1

当一个进程终止时,内核自动关闭它所打开的文件,很多程序利用了这一功能而不是显式地用close关闭文件

lseek函数

每个打开的文件都有一个与其相关联的当前文件偏移量,用以度量从文件开始处计算的字节数,通常,读写操作都从当前文件偏移量处开始。当打开一个文件时,除非指定O_APPEND选项,否则该偏移量被设置为0.调用lseek函数显式地为一个打开的文件设置偏移量

#include <unistd.h>

off_t lseek(int fieldes,off_t offset,int whence)//若成功则返回新的文件偏移量,若出错则返回-1

对offset的解释与参数whence值有关。

1.若whence是SEEK_SET,则将该文件的偏移量设置为距文件开始处offset个字节

2.若whence是SEEK_CUR,则将该文件的偏移量设置为其当前值加offset,offset可正可负

3.若whence是SEEK_END,则将该文件的偏移量设置为文件长度加offset,offset可正可负

确定打开文件的当前偏移量:

off_t currpos;

currpos=lseek(fd,o,SEEK_CUR);

可用上述方法来确定所涉及的文件是否可以设置偏移量。如果文件描述符引用的是一个管道、FIFO或网络套接字,则lseek返回-1,并将errno设置为ESPIPE(why?)

lseek仅将当前的文件偏移量记录在内核中,它并不引起任何I/O操作。文件偏移量可以大于文件的当前长度,在这种情况下,对该文件的下一次写将加长该文件,并在文件中构成一个空洞,这一点是允许的,位于文件中但没有写过的字节都被读为0.文件中的空洞并不要求在磁盘上占用存储区。

read函数:从打开文件中读数据

#include <unistd.h>

ssize_t read(int filedes,void *buf,size_t nbytes);//nbytes为要求读的字节数

如read成功,则返回读到的字节数,如已到达文件结尾,则返回0,若出错,则返回-1

write函数:向打开的文件写数据

#include <unistd.h>

ssize_t write(int filedes,const void *buf,size_t nbytes);//若成功则返回已写的字节数,若出错则返回-1

该函数返回值通常与参数nbytes的值相同,否则表示出错。

参考:

http://blog.sina.com.cn/s/blog_4697cdcd0100s3uh.html

APUE第三章

【APUE】文件I/O的更多相关文章

  1. APUE 文件IO

    文件 IO 记录书中的重要知识和思考实践部分 Unix 每个文件都对应一个文件描述符(file descriptor),为一个非负整数,一个文件可以有多个fd, 后面所有与文件(设备,套接字等)有关操 ...

  2. [APUE] 文件 I/O

    文件操作相关 API:open, read, write, lseek, close. 多进程共享文件的相关 API:dup, dup2, fcntl, sync, fsync, ioctl. 文件操 ...

  3. [apue] 文件中的空洞

    空洞的概念 linux 上普通文件的大小与占用空间是两个概念,前者表示文件中数据的长度,后者表示数据占用的磁盘空间,通常后者大于前者,因为需要一些额外的空间用来记录文件的某些统计信息或附加信息.以及切 ...

  4. [APUE]文件和目录(下)

    一.mkdir和rmdir函数 #include <sys/types.h> #include <sys/stat.h> int mkdir(const char *pathn ...

  5. [APUE]文件和目录(中)

    一.link.unlink.remove和rename 一个文件可以有多个目录项指向其i节点.使用link函数可以创建一个指向现存文件连接 #include <unistd.h> int ...

  6. [APUE]文件和目录(上)

    一.文件权限 1. 各种ID 我在读这一章时遇到了各种ID,根据名字完全不清楚什么意思,幸好看到了这篇文章,http://blog.csdn.net/ccjjnn19890720/article/de ...

  7. APUE 文件和目录

    文件和目录 Unix 所有的文件都对应一个 struct stat,包含了一个文件所有的信息. #include <sys/stat.h> struct stat { mode_t st_ ...

  8. APUE ☞ 文件和目录

    粘着位(Sticky Bit) S_ISVTX位被称为粘着位.如果一个可执行程序文件的这一位被设置了,程序第一次运行完之后,程序的正文部分的一个副本仍被保存在交换区(程序的正文部分是机器指令).这使得 ...

  9. APUE学习笔记-一些准备

    从开始看APUE已经有快一个星期了,由于正好赶上这几天清明节放假,难得有了三天空闲假期可以不受打扰的学习APUE,现在已经看完前六章了,里面的大部分例程也都亲自编写,调试过了.但总觉得这样学过就忘,因 ...

  10. 配置apue的头文件apue.h和unp的头文件anp.h

    配置apue的头文件apue.h和unp的头文件anp.h 如果要使用gcc -g 来生成可调试文件一定要修改Make.defines.linux文件中的CFLAGS变量 修改为:CFLAGS=-an ...

随机推荐

  1. HTTP隧道代理

    reGeorg的前身是2008年SensePost在BlackHat USA 2008 的 reDuh延伸与扩展.也是目 前安全从业人员使用最多,范围最广,支持多丰富的一款http隧道.从本质上讲,可 ...

  2. 安装 Zend Studio 报错:0x80070666

    出现 0x80070666 报错时 查看日志文件,发现调用VC14(即:Microsoft Visual C++ 2015 Redistributable)时,出错返回0x666 先卸载原有的VC14 ...

  3. python基础一 day7 复习文件操作

    read()原样输出 读取出来的是字符串类型 readline()输出一行 读取出来的是字符串类型 readlines()把每行文本作为一个字符串存入列表,并返回列表 打开方式: b以bytes类型打 ...

  4. 1.ssm web项目中的遇到的坑--自定义JQuery插件(slide menu)

    自定义的JQuery插件写的回调函数不执行: 写好了回调函数,将函数打印出来是原形,就是不执行 function () { console.log("---onClickItem---&qu ...

  5. 用固定长度的数组实现stack queue

    package my_basic.class_3; /** * 用数组结构实现大小固定的队列和栈 */ public class Code_01_Array_stack_queue { public ...

  6. process data

    # version 1.0def connect_mysql(sql, oper_type="select", data_l=None): conn = pymysql.conne ...

  7. VS2015安装SVN插件

    一.下载VISUALlSVN 官网下载:地址 选择[VisualSVN for Visual Studio 2015 and older]的下载按钮下载,目前版本号VisualSVN 5.1.9,支持 ...

  8. 全局/局部变量、宏、const、static、extern

    #pragma mark--全局变量和局部变量 根据变量的作用域,变量可以分为: 一.全局变量 1> 定义:在函数外面定义的变量2> 作用域:从定义变量的那一行开始,一直到文件结尾(能被后 ...

  9. L2-2 社交集群 (25 分)(一个写挫的并查集)

    题目: 思路: 就是一个并查集的裸题,不过在数据查找方面可能不好处理,暴力完全可以解决这个问题啊!! #include <bits/stdc++.h> #include <cstdi ...

  10. Firefox--摄像头麦克风权限

    在自动化测试的过程中,可能会遇到来自浏览器的权限提示(摄像头.麦克风),今天,就讨论一下如何结局这个问题. 先来认识一下来自Firefox的权限提示,访问一个需要摄像头或者麦克风的网站 你可能觉得,一 ...