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. autoHeight.vue 高度自适应

    autoHeight.vue 高度自适应 <!-- * @description 自适应高度 * @fileName autoHeight.vue * @author 彭成刚 * @date 2 ...

  2. vue+Java 前后端分离,多次请求Session不一致的问题(网络上找的)

    在vue main.js中增加以下配置: import axios from 'axios'; axios.defaults.withCredentials=true; 请求时:设置 withCred ...

  3. PHP03 移动互联网和PHP

    学习要点 移动互联网 云计算 网络通信协议 Apache http服务器 PHP运行原理 学习目标 理解网络通信协议 掌握PHP运行原理 WAMP开发环境的搭建   移动互联网 定义 移动互联网,就是 ...

  4. 数据库课程设计 PHP web实现

    纪念一下自己写的东西.. 都说很垃圾就是了 直接用XAMPP做的 菜鸟网上学的PHP和HTML <!DOCTYPE html> <html> <head> < ...

  5. HLS协议详解

    1. HLS HLS是为移动设备开发的基于HTTP的流媒体解决方案. 2. 原理: 将视频或流切分成小片(TS), 并建立索引(M3U8). 支持视频流:H.264: 音频流:AAC 3. M3U8文 ...

  6. jqury 延迟方法

    $("button").click(function(){    $("#div1").delay("slow").fadeIn();    ...

  7. 分享下找到的Github上大神的EmpireofCode进攻策略:反正我是用了没反应,改了代码后单位不进攻,蠢站在那里,我自己的策略调调能打败不少人,这个日后慢慢研究吧,Github上暂时找到的唯一策略

    from queue import PriorityQueue from enum import Enum from battle import commander from battle impor ...

  8. C语言 NULL 是什么鬼

    NULL , 0 , '\0'  之间的区别与联系 1.NULL 结构体的使用中,都可以用NULL表示空,那么NULL是什么 #ifndef __cplusplus #define NULL ((vo ...

  9. C#如何根据DataTable生成泛型List或者动态类型list

    背景:在项目中,sql语句检索返回DataTable,然后根据检索结果做进一步的操作,本篇文章即是介绍如何将DataTable快速生成泛型List返回. 假设存在如下学生类: public class ...

  10. Nginx的启动过程

    主要介绍Nginx的启动过程,可以在/core/nginx.c中找到Nginx的主函数main(),那么就从这里开始分析Nginx的启动过程. 涉及到的基本函数 源码:  View Code Ngin ...