Linux学习-课时13-Linux文件与IO编程

曾巧文 发布于:2012-5-24 23:31 分类:Linux学习 标签: Ubuntu linux 课时

Linux文件与IO编程
理解Linux编程的一些基础概念
掌握open、close、read、write、lseek函数的使用

1、Linux编程基础概念
系统调用
所谓系统调用是指操作系统提供给用户程序调用的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得操作系统内核提供的服务。例如用户可以通过进程控制相关的系统调用来创建进程、实现进程调度、进程管理等。


2、内核空间和用户空间
为了更好地保护内核空间,将程序的运行空间分为内核空间和用户空间(也就是常称的内核态和用户态),它们分别运行在不同的级别上,在逻辑上是相互隔离的。因此,用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间的函数。


3、系统调用的应用场景
在有些情况下,用户空间的进程需要获得一定的系统服务(调用内核空间程序),这时操作系统就必须利用系统提供给用户的“特殊接口”——系统调用规定用户进程进入内核空间的具体位置。进行系统调用时,程序运行空间需要从用户空间进入内核空间,处理完后再返回到用户空间。


4、用户编程接口
系统调用并不是直接与程序员进行交互的,它仅仅是一个通过软中断机制向内核提交请求,以获取内核服务的接口。
在实际使用中程序员调用的通常是用户编程接口——API。
每个系统调用在libc库中设置了一个具有相同名字的函数,程序员可以通过这些接口调用系统调用。
很多ANSI C标准的通用库函数也是通过调用系统调用实现其自身功能的。如: printf函数会调用write系统调用实现其自身功能


5、库函数与系统调用的层次

 

Linux学习-课时13-Linux文件与IO编程



获取帮助信息
man 2 open (2表示系统调用函数)
man 3 fopen (3表示标准库函数)
参考手册
安装中文man :
sudo apt-get install manpages-zh


Unbuffered I/O函数
C标准I/O函数与Unbuffered I/O函数
open、read、write、close等系统函数称为无缓冲I/O(Unbuffered I/O)函数,因为它们位于C标准库函数fopen、fclose的I/O缓冲区的底层。用户程序在读写文件时既可以调用C标准I/O库函数,也可以直接调用底层的UnbufferedI/O函数。
C标准库函数是C标准的一部分,而Unbuffered I/O函数是UNIX标准的一部分,在所有支持C语言的平台上应该都可以用C标准库函数,而只有在UNIX平台上才能使用Unbuffered I/O函数。
在Windows上,标准I/O库的底层是Win32 API支持实现的,如读写文件的系统函数是ReadFile、WriteFile。
Unbuffered I/O函数
文件描述符
每个进程在Linux内核中都有一个结构体来维护进程相关的信息,称为进程描述符(进程控制块PCB),
进程描述符中有一个指针指向一张称为文件描述符表(FDT)的结构体,文件描述符表中每一项都包含一个文件描述符 (非负整数)及指向该文件表项的指针。
Unbuffered I/O函数
文件描述符
用户程序不能直接访问内核中的文件描述符表,而只能使用文件描述符(非负整数)。
当调用open打开一个文件或创建一个新文件时,内核分配一个文件描述符并返回给用户程序,该文件描述符表项中的指针指向新打开的文件。
当读写文件时,用户程序把文件描述符传给read或write,内核根据文件描述符找到相应的表项,再通过表项中的指针找到相应的文件。

Unbuffered I/O函数文件描述符
程序启动时会自动打开三个文件:标准输入、标准输出和标准错误输出。
C标准库的stdio.h头文件中分别用FILE *指针stdin、stdout和stderr表示。
在liunx下这三个文件的描述符分别是0、1、2。在unistd.h头文件中有如下的宏定义
Unbuffered I/O函数
open函数
open函数是用于打开或创建文件,在打开或创建文件时可以指定文件的属性及用户的权限等各种参数。
函数原型:

 


Unbuffered I/O函数
open函数说明
返回值:成功返回新分配的文件描述符,出错返回-1
/* mode_t mode */ 表示此参数可无。
pathname参数是要打开或创建的文件名的字符串,可使用绝对路径或者相对路径。
flags参数有一系列常数值可供选择,可以同时选择多个常数用按位或运算符连接起来,所以这些常数的宏定义都以O_开头,表示or。
参数mode指定文件权限,可以用八进制数表示,比如0644表示-rw-r--r--,也可以用S_IRUSR、S_IWUSR等宏定义按位或起来表示。要注意的是,文件权限由open的mode参数和当前进程的umask掩码共同决定。( mode & ~umask )

 

Unbuffered I/O函数
open函数说明 : flags参数
必选项:以下三个常数中必须且只能指定一个:O_RDONLY 只读打开;O_WRONLY 只写打开;O_RDWR 可读可写打开
以下可选项可以同时指定0个或多个。
O_APPEND 表示追加。如果文件已有内容,这次打开文件所写的数据附加到文件的末尾。
O_CREAT 若此文件不存在则创建它。使用此选项时需提供第三个参数mode,设置文件的访问权限。
O_EXCL 如果同时指定了O_CREAT,并且文件已存在,则出错返回。
O_TRUNC 如果文件已存在,并且以只写或可读可写方式打开,则将其长度截断为0字节。

 

Unbuffered I/O函数
close函数
close函数是用于关闭一个打开文件。当一个进程终止时,它所有已打开的文件都由内核自动关闭。但是对于一个长年累月运行的程序,打开的文件描述符一定要及时关闭。
函数原型:

 

返回值:成功返回0,出错返回-1
参数fd是要关闭的文件描述符。

Unbuffered I/O函数
示例:创建一个空文件

Unbuffered I/O函数
read函数
用于将指定的文件描述符中读出数据。当从终端设备(everything is file)文件中读出数据时,通常一次最多读一行。
函数原型:

 

返回值:成功返回读取的字节数,出错返回-1,如果在调read之前已到达文件末尾,则这次read返回0

Unbuffered I/O函数
read函数说明
fd 文件描述符
buf 指向缓冲区的指针
count 是请求读取的字节数
注意:有些情况下,实际读到的字节数(返回值)会小于请求读的字节数count
读常规文件时,在读到count个字节之前已到达文件末尾。例如,距文件末尾还有30个字节而请求读100个字节,则read返回30,下次read将返回0
从终端设备读,通常以行为单位,读到换行符就返回
从网络读,根据不同的传输层协议和内核缓存机制,返回值可能小于请求的字节数。



write函数
用于向打开的文件写数据,写操作从文件的当前位移量处开始。
函数原型:

 

返回值:成功返回写入的字节数,出错返回-1。
write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。文件读写位置也会改变
写常规文件时,write的返回值通常等于请求写的字节数count,而向终端设备或网络写则不一定。
Unbuffered I/O函数
示例:
复制文件

Unbuffered I/O函数
lseek函数
每个打开的文件都记录着当前的读写位置,打开文件时读写位置是0,通常读写多少个字节就会将读写位置往后移多少个字节。lseek函数可以移动当前读写位置(或者叫偏移量)。
函数原型:


Unbuffered I/O函数
lseek函数说明
返回值  当调用成功时则返回目前的读写位置,也就是距离文件开头多少个字节。若有错误则返回-1 。
fd 文件描述符
offset 根据参数whence来移动读写位置的偏移量,单位是字节、数值上可正可负。
参数  whence为下列其中一种:
SEEK_SET 参数offset即为新的读写位置。
SEEK_CUR 以目前的读写位置偏移offset个字节。
SEEK_END 以文件尾后位置偏移offset个个字节。
常规文件都可以设置偏移量,设备一般是不可以设置偏移量的。如果设备不支持lseek,则lseek返回-1

 

Unbuffered I/O函数
示例:
观察读写位置

同步阻塞IO和同步非阻塞IO
同步阻塞(Synchronous Block)IO
如果从终端输入的数据没有换行符,调用read方法读终端设备时就会阻塞,如果网络上没有接收到数据包,调用read方法从网络读就会阻塞。
当进程调用一个阻塞的系统函数时,该进程被置于睡眠(Sleep)状态,这时内核调度其它进程运行,直到该进程等待的事件发生了,它才有可能继续运行。
与Sleep状态对应的是Running状态,在Linux内核中,处于运行状态的进程分为两种情况:
正在被调度执行,即获得CPU时间片,执行代码
就绪状态,该进程不需要等待什么事件发生,随时都可以执行,但CPU暂时还在执行另一个进程,所以该进程在一个就绪队列中等待被内核调度。


同步阻塞IO和同步非阻塞IO
同步阻塞IO
程序调用read时切换到睡眠等待状态,直到在标准输入设备输入了换行符后,才能执行完read。
read只读取了10个字符,标准输入缓冲中还有字符d和回车
程序执行完毕,Shell进程恢复运行,从输入缓冲从读取剩余内容。
同步阻塞IO和同步非阻塞IO
同步非阻塞IO
如果在open一个设备时指定了O_NONBLOCK标志,read/write就不会阻塞。
当请求的I/O操作不能完成时,则不让进程睡眠,而是返回一个错误。
例如read:如果设备暂时没有数据可读就返回-1,同时置errno为EWOULDBLOCK(EAGAIN)。表示本来应该阻塞,但事实上并没有阻塞而是直接返回错误,调用者可试着再读一次。

同步阻塞IO和同步非阻塞IO
同步非阻塞IO :轮询模式
如果是使用阻塞性read,则在设备1数据没有到达之前,程序的执行会停在语句2处,设备2无法读。
如果是使用非阻塞性read,则在设备1数据没有到达之前,会检测设备2数据是否到达。
如所有设备数据没有到达,可显式让程序sleep。
同步阻塞IO和同步非阻塞IO
同步非阻塞IO 示例
同步阻塞IO和同步非阻塞IO
同步阻塞IO模型的典型流程
同步阻塞IO和同步非阻塞IO
同步非阻塞IO的典型流程

版权所有:《曾巧文博客-关注互联网IT技术,记录生活点滴》 => 《Linux学习-课时13-Linux文件与IO编程
本文地址://qiaowen.net/post-1232.html
除非注明,文章均为 《曾巧文博客-关注互联网IT技术,记录生活点滴》 原创,欢迎转载!转载请注明本文地址,谢谢。

有 5563 人浏览,获得评论 1 条

评论:

万屏科我
2013-12-14 14:29
不是很明白啊。

发表评论:

Powered by emlog 粤ICP备12040901号

>>本作品采用-知识共享署名-非商业-禁止演绎-协议-进行许可 |站点地图 | | | | 开放分类目录 |