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. dircolors - 设置‘ls'显示结果的颜色

    SYNOPSIS[总览] dircolors [-b] [--sh] [--bourne-shell] [-c] [--csh] [--c-shell] [-p] [--print-database] ...

  2. jquery点击tr换背景颜色

    jquery点击tr换tr的背景颜色,table的id为db-list1jQuery(function() { jQuery("#db-list1 tr").click( func ...

  3. ios之UITextfield (2)

    UItextField通常用于外部数据输入,以实现人机交互.下面以一个简单的登陆界面来讲解UItextField的详细使用. //用来显示“用户名”的label UILabel* label1 = [ ...

  4. Shell读取一个表达式并计算其结果

    #!/bin/bash # 读取一个算数表达式并计算出结果 # 如果输入 # 5+50*3/20 + (19*2)/7 # 则结果为 # 17.929 read x printf "%.3f ...

  5. bzoj 1098 [POI2007] 办公楼 biu

    # 解题思路 画画图可以发现,只要是两个点之间没有相互连边,那么就必须将这两个人安排到同一个办公楼内,如图所示: 那,我们可以建立补图,就是先建一张完全图,然后把题目中给出的边都删掉,这就是一张补图, ...

  6. PyQt5-Python3-PyCharm 配置

    File->Tools->External Tools->add 配置ui文件转换工具 Name: PyUIC Program: D:\develop\python\Mac\venv ...

  7. CentOS 6.5 x64 安装Tomcat8 并配置两个Tomcat8

    1.首先,安装tomcat的前提是已经配置好jdk环境变量,若没配好可以参考我的上一篇博文:CentOS 6.5 x64安装jdk8,当然也可以通过网络搜索安装步骤~~ 2.下载: 可以通过官网下载: ...

  8. 有关OEP脱壳

    首先补充: OEP:(Original Entry Point),程序的入口点,软件加壳就是隐藏了OEP(或者用了假的OEP), 只要我们找到程序真正的OEP,就可以立刻脱壳. PUSHAD (压栈) ...

  9. 【转】Entity Framework6 with Oracle(可实现code first)

    Oracle 已在2014年底提供对EF6的支持.以前只支持到EF5.EF6有很多有用的功能 值得升级.这里介绍下如何支持Oracle   一.Oracle 对.net支持的一些基础知识了解介绍. 1 ...

  10. python010 Python3 元组

    Python3 元组Python 的元组与列表类似,不同之处在于元组的元素不能修改.元组使用小括号,列表使用方括号.元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可.如下实例: tup1 = ...