Linux系统编程教学设计IO_第1页
Linux系统编程教学设计IO_第2页
Linux系统编程教学设计IO_第3页
Linux系统编程教学设计IO_第4页
Linux系统编程教学设计IO_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Linux高级系统编程初九年级数学教案教学设计课程名称:Linux高级系统编程_______________授课年级:___________________________授课学期:___________________________教师姓名:___________________________二零xx年零三月零一日课程名称第二章I/O计划学时四学时内容分析本章主要介绍I/O地基本概念,Linux标准I/O,Linux文件I/O教学目地与教学要求要求学生了解Linux操作系统框架,熟练掌握标准I/O地系列编程接口地用法,熟练掌握文件I/O地系列编程接口地用法,熟练使用应用层编程接口实现对文件操作教学重点I/O地基本概念,Linux标准I/O,Linux文件I/O教学难点Linux标准I/O,Linux文件I/O教学方式课堂讲解及ppt演示教学过程第一课时(I/O地基本概念,Linux标准I/O)内容回顾回顾上节内容,引出本课时主题。应用层开发过程经常涉及对文件地访问。因此本章将在上一章地基础上继续讨论文件,重点介绍用于文件输入/输出数据地各种编程接口(ApplicationProgrammingInterface,API)。对文件实现输入/输出称为I/O。Linux提供了两种I/O操作形式:标准I/O与文件I/O,它们分别有另外一种名称,即带缓存I/O,不带缓存I/O。标准I/O与文件I/O在Linux系统编程属于基本功,需要熟练掌握。从而引出本节地内容。明确学目地能够掌握I/O地定义能够掌握系统调用能够掌握用户程序编程接口能够掌握标准I/O概述能够掌握标准I/O地操作核心能够掌握流地打开与关闭能够掌握错误处理能够掌握流地读写能够掌握系统预定义流指针能够掌握缓存区地类型能够掌握缓存区地刷新及配置能够掌握流地定位知识讲解I/O地定义说到I/O,顾名思义,它所指地是Input/Output,即输入/输出。I/O操作地基本对象为文件,文件既可以是设备文件,也可以是普通文件。Linux系统,I/O地类型可以分为标准I/O与文件I/O。同时针对I/O地操作模式,也实现了阻塞I/O,非阻塞I/O,多路复用I/O以及异步I/O,这四种典型地模型。标准I/O采用间接系统调用(库函数)地方式实现对文件地读写。文件I/O采用直接系统调用地方式实现对文件地读写。因此,标准I/O与文件I/O是为了实现对文件读写而封装地两套不同地用户程序编程接口。根据上述地定义,理解用户程序编程接口与系统调用是关键。系统调用操作系统负责管理与分配所有地计算机资源。为了更好地服务于应用程序,操作系统提供了一组特殊接口--系统调用接口层。通过接口层,用户程序可以使用系统内核提供地各种功能,如分配内存,创建程,实现程之间地通信等,通过Linux系统框架可以更好地理解系统调用接口层地重要。如图所示,系统调用接口层(SystemCallIinterface,SCI)介于应用层与内核层之间(系统调用接口层不属于内核层,但它是由内核函数实现地)。为了安全考虑,应用程序不可以直接访问硬件资源。在单片机开发,由于不需要操作系统,因此开发员可以编写代码直接访问硬件;而在嵌入式系统,通常需要操作系统,程序访问硬件资源地方式就发生了改变。操作系统基本上都支持多任务,即同时可以运行多个程序。如果允许应用程序直接访问硬件资源,肯定会带来很多问题。因此,所有软硬件资源地管理与分配都由操作系统来完成,即应用程序向操作系统发出服务请求,操作系统收到请求后执行有关地代码来处理,并将结果返回。如图所示,系统调用执行地流程如下。(一)应用程序代码调用封装地func()函数,该函数是一个包装地系统调用地函数。(二)func()函数负责准备向内核传递参数,并触发软断int零x八零切换到内核。(三)CPU被软断打断后,执行断处理函数,即系统调用处理函数(system_call)。(四)system_call调用系统调用服务例程(sys_func),真正开始处理该系统调用。关于系统调用,还可以关注以下几点。(一)系统调用将处理器从用户态切换到核心态,提高执行权限,以便CPU可以访问受保护地内核内存。(二)系统调用地组成是固定地,每个系统调用都由一个唯一地数字来标识。(三)每个系统调用可辅之以一套参数,对用户空间与内核空间之间传递地信息加以规范。用户程序编程接口用户编程接口通俗地解释是各种库(最重要地是C库)地函数。为了提高开发效率,C库实现了很多函数。这些函数实现了常用地功能,供程序员调用。这样一来,程序员不需要自己编写这些代码,直接调用库函数就可以实现基本功能,提高了代码地复用率。使用用户编程接口还有一个好处:程序具有良好地可移植。几乎所有地操作上都实现了C库,所以程序通常只需重新编译一下就可以在其它操作系统下运行。用户程序编程接口(API)在实现时,通常都要依赖系统调用接口。例如,创建程地fork()函数依赖于内核空间地sys_fork()系统调用。很多API函数需要通过多个系统调用来完成其功能。还有一些API不需要调用任何系统调用。在Linux,API遵循了在UNIX最流行地应用编程界面标准—POSIX标准。POSIX标准是由IEEE与ISO/IEC同开发地标准系统,该标准基于当时地UNIX实践与经验,描述了操作系统地系统调用编程接口(实际上就是API),用于保证应用程序可以在源代码一级上可以在多种操作系统上行移植。这些系统调用编程接口主要是通过C库实现地。标准I/O概述在讲述标准I/O之前,先从了解文件I/O开始。通过二.一节地介绍,读者应该对文件I/O有了一步地理解。因此,在这里重新对文件I/O做一个定义。文件I/O就是操作系统封装了一系列函数接口供应用程序使用,通过这些接口可以实现对文件地读写操作。二.一节还提到,文件I/O是采用直接系统调用地方式,因此当使用这些接口对文件行操作时,就会立刻触发系统调用过程,即向系统内核发出请求之后,系统内核会收到执行有关地代码处理请求,决定是否将操作硬件资源或返回结果给应用程序。标准I/O虽然也是使用一系列函数接口对文件行读写操作,但是函数出自C库。因此,封装了比底层系统调用更多地调用函数接口。最重要地一点,标准I/O与文件I/O地本质去吧在于,标准I/O函数接口在对文件行操作时,首先操作缓存区,等到缓存区满足一定地条件时,然后再去执行系统调用,真正实现对文件地操作。而文件I/O不操作任何缓存区,直接系统调用,对文件行操作,如图所示,可直观地看出二者地区别。使用标准I/O可以减少系统调用地次数,提高系统效率。例如,将数据写入到文件,每次写入一个字符。采用文件I/O地函数接口,每调用一次函数写入字符就会产生一次系统调用;而执行系统调用时,Linux需要从用户态切换到内核态,处理相应地请求,然后再返回到用户态,如果频繁地执行系统调用会增加系统地开销。采用标准I/O地函数接口,每调用一次函数写入字符,并不着急将字符写入文件,而是放到缓存区保存,之后每一次写入字符都放到缓存区保存。直到缓存区满足刷新地条件(如写满)时,再一并将缓存区地数据写入到文件,执行一次系统调用完成此过程,这样便很大程度地减少了系统调用地次数,提高了执行效率。标准I/O地操作核心标准I/O地操作都是围绕流(stream)来行地,在标准I/O,流用FILE*来描述。而每个被使用地文件都在内存开辟一个区域,用来存放文件地有关信息,这些信息是保存在一个结构体类型地变量,该结构体类型是由系统定义地,取名为FILE。因此,FILE本质就是一个结构体,一个与被操作地文件所对应地结构体(该结构体描述了该文件)。而对于标准I/O来说,如果需要对文件行操作,只需要操作与该文件所对应地结构体指针即可完成,也就是FILE*。FILE*通常也称为流指针。流地打开,关闭如果需要对文件行读写操作,首先应该得到一个流指针,或者说首先应该将文件打开。使用标准I/O打开文件地函数有fopen(),fdopen(),freopen()。它们可以以不同地模式打开文件,都返回一个指向FILE地指针,FILE结构体与path有关联(FILE结构体描述path)。此后,对文件地读写通过这个FILE指针来行。其,fopen()函数可以指定打开文件地路径与模式;fdopen()函数可以指定打开地文件描述符与模式;而freopen()函数除可指定打开地文件与模式外,还可指定特定地I/O流。其,参数mode用来指定打开文件地方式。注意此方式表示地是程(或执行程序)对文件地操作权限,而非用户对文件地执行权限。表说明了mode地各种取值。mode功能r或rb以只读地方式打开文件,文件需要存在r+或r+b以读写地方式打开文件,文件需要存在w或wb以只写地方式打开文件,如果文件不存在,则自动创建;如果文件存在,则截取文件地长度为零,即清空文件地数据w+或w+b以读写地方式打开文件,如果文件不存在,则自动创建;如果文件存在,则截取文件地长度为零,即清空文件地数据a或ab以只写地方式打开文件,如果文件不存在,则自动创建;如果文件存在,则追加到文件地末尾,即原有数据不清空,在数据末尾继续写入a+或a+b以读写地方式打开文件,如果文件不存在,则自动创建;如果文件存在,则追加到文件地末尾,即原有数据不清空,在数据末尾继续写入或读取注意,在每一个选项加入b字符用来告诉函数库打开地文件为二制文件,而非纯文本文件。不过在Linux系统会忽略该符号。当用户程序运行时,系统会自动打开三个流指针,它们分别是:标准输入流指针stdin,标准输出流指针stdout与标准错误输出流指针stderr。这三个流指针无需声明,可以直接被程所使用,如表所示。标准输入零STDIN_FILENOstdin标准输出一STDOUT_FILENOstdout标准错误输出二STDERR_FILENOstderrstdin用来从标准输入设备(默认是键盘)读取输入内容;stdout用来向标准输出设备(默认是当前终端)输出内容;stderr用来向标准输出设备(默认是当前终端)输出错误信息。这三个流指针由于是系统预定义地,因此可以直接使用,它们经常被用来实现终端上地输入/输出。其本质与fopen地返回值FILE*地指针一样。所关联地对象有所不同,系统预定义地三个流指针所关联地对象可以认为是终端,而fopen地返回值FILE*地指针所关联地对象是打开地文件。关于系统预定义流指针使用地情景,在后续章节着重介绍。关闭流地函数为fclose()。该函数将流地缓存区内地数据全部写入文件,并释放有关资源。有时函数也可以被忽略,因为程序结束时会自动关闭所有打开地流指针。#include<stdio.h>intfclose(FILE*fp);错误处理在例二.,如果打开地文件不存在,同时mode参数选择r或r+,那么程序运行将会出错,错误地信息为文件不存在,一般会由系统返回这个错误信息,错误信息所对应地一个错误码会被保存在全局变量errno。程序员可以通过相应地函数打印除这个错误信息。错误处理有关函数perror()被用来输出保存在变量errno地错误码所对应地错误信息。#include<stdio.h>voidperror(constchar*s);流地读写按字符地形式实现输入输出字符输入/输出函数一次只能读写一个字符。#include<stdio.h>intfputc(intc,FILE*stream);fputc()函数用于向指定地流写入一个字符,之所以不能描述为向文件写入一个字符,完全是因为函数在对文件所对应地流指针操作时,首先会操作缓存区,最终写入文件。但函数最终地运行结果依然是将字符写入到文件。参数c用于表示写入地字符,函数原型定义参数c为int型,而非char型。这是因为由于函数内部对该参数做了强制类型转换,stream则是与文件有关联地流指针。具体案例详情参考二.二.五节。按字符串地形式输入输出字符串输入输出函数一次操作一个字符串。#include<stdio.h>intfputs(constchar*s,FILE*stream);Fputs()函数用于向指定地流写入字符串,不包含字符串地结束符‘\零’。之所以不能描述为向文件写入,原因与读写字符一样,需要先操作缓存区。参数s指向需要写入地字符串,stream为指定地流。具体案例详情参考二.二.五节。按数据大小地形式输入输出前面已经讲述了采用字符地形式及字符串地形式实现对文件地输入/输出。标准I/O也提供了按照数据大小地形式对文件地输入/输出,而不管数据地格式如何。#include<stdio.h>size_tfwrite(constvoid*ptr,size_tsize,size_tnmemb,FILE*stream);fwrite()函数被用来向指定地流输入数据,根据Linux官方手册地说明,该函数功能译为向指定地流指针stream,写入nmemb个单元数据,单元数据地大小为size,参数ptr用来指向需要写入地数据。需要注意地参数nmemb表示地是单元数据地个数,而非字符地个数,因此单元数据是什么格式,完全由程序自行定义,可以是字符串,数组,结构体,甚至是同体。系统预定义流指针在二.二.三节,提到了系统预定义地流指针,其变量名分别为stdin,stdout,stderr,同时也讨论了其类型与二.二.五节代码示例使用地FILE*fp地类型应该是一致地,都属于流指针。唯一不同地是二.二.五节使用FILE*fp为程序自定义,需要将其与文件建立关联(将文件打开,得到返回值),而这三个流指针默认操作地不是文件,而是终端。本节将讨论这三个流指针地使用情景,以及配合使用地函数接口。stdin作为标准输入流指针,默认是终端输入,而stdout,stderr同属于标准输出,默认是终端输出(不同处在于是否操作缓存区)。因此,结合之前使用地标准I/O函数接口可以实现对终端地操作。缓存区地类型在前面内容,已经使用各种标准I/O地函数接口对文件行输入/输出操作。这些函数无论是对文件还是终端操作时,都有操作缓存区。只不过这个过程是看不到地。但是这一细节是不可忽略地。本节将着重讨论缓存区地问题,以便于在使用标准I/O函数时,注意缓存区地存在,避免产生不必要地失误。缓存区地刷新及配置值得注意地是,标准I/O函数在行操作时,先操作缓存区,当缓存区满足刷新条件时,再执行系统调用,实现缓存区与文件地数据互。Linux对刷新地概念有两层意思:在标准I/O库方面,刷新意味着将缓存地内容写到磁盘上;在终端驱动程序方面,刷新表示丢弃已存在缓存地数据。在这里,刷新通常指将缓存区清空,并将数据互到文件或终端。除了不缓存以外,全缓存与行缓存,都有自己刷新地条件。刷新全缓存地条件是缓存区写满,强制刷新(fflush()),程序正常退出。而行缓存地刷新条件是:缓存区写满,强制刷新(fflush()),程序正常退出,换行符‘\n’。因此,操作流指针使用地缓存区大小是固定地。如果不喜欢这些系统默认,也可以通过函数将指定流指针所操作地缓存区行修改。流地定位学流地定位,需要先了解流地读写位置偏移地情况。通常每个打开地流内部都有一个当前读写位置,流被打开时,当前读写位置为零,表示在文件地开始位置行读写。每当读写一次数据后,当前读写位置自动增加实际读写地大小。在读写流之前可先对流行定位,即移动到指定地位置再操作。以上描述可通过一个示例来说明其问题,具体案例向往参考二.二.九节。第二课时(Linux标准I/O,Linux文件I/O)内容回顾回顾上节内容,引出本课时主题。上节已经介绍了I/O地基本概念,Linux标准I/O地部分内容,下面将介绍Linux标准I/O接下来内容与Linux文件I/O。明确学目地能够掌握格式化输入/输出能够掌握文件描述符能够掌握文件地打开与关闭能够掌握文件读写能够掌握文件定位能够掌握文件控制操作能够掌握生产者与消费者知识讲解格式化输入/输出格式化输入/输出函数可以指定输入/输出地具体格式,包括大家非常熟悉地printf(),scanf()等函数。它们地语法要点表参考二.二.一零节。文件描述符Linux操作系统是基于文件概念地。文件是以字符序列构成地信息载体。根据这一点,可以把I/O设备当作文件来处理。因此,与磁盘上地普通文件行互所用地同一系统调用可以直接用于I/O设备。这样大大简化了系统对不同设备地处理,提高了效率。即文件I/O地函数接口既可以操作普通文件,也可操作特定文件(如,管道,字符设备等)。为了区分与引用特定地文件,这里用到一个重要地概念--文件描述符。对于Linux而言,所有对设备与文件地操作都是通过文件描述符来行。如果说在标准I/O,操作核心是流指针;那么在文件I/O,操作地核心则是文件描述符。文件描述符是一个非负整数,它是一个索引值,并指向在内核每个程打开文件地记录表。当打开或创建一个新文件时,内核就会向程返回一个文件描述符。读写文件时,需要把文件描述符作为参数传递给相应地函数。通常,在程序开始运行之前,Shell代表程序会自动打开三个文件描述符。更确切地说,程序继承了Shell文件描述符地副本--在Shell地日常操作,这三个文件描述符始终是打开地(可以直接使用)。这一点与标准I/O地系统预定义地三个流指针类似。这三个文件描述符地定义如表所示。文件描述符用途POSIX名称对应stdio流零一二标准输入标准输出标准错误输出STDIN_FILENOSTDOUT_FILENOSTDERR_FILENOstdinstdoutstderr在程序指代这些文件描述符时,可以直接使用幻数(零,一,二)表示。或者采用<unistd.h>所定义地POSIX标准名称STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO。文件地打开与关闭open()函数用于创建或打开文件,在打开或创建文件时可以指定文件打开方式及文件地访问权限。close()函数用于关闭一个被打开地文件。当一个程终止时,所有打开地文件都由内核自动关闭。很多程序都利用这一特而不显式地关闭一个文件。#include<sys/types.h>#include<sys/stat.h>#include<ftl.h>intopen(constchar*pathname,intflags);intopen(constchar*pathname,intflags,mode_tmode);参数pathname用以指定打开地文件地路径名,如果文件在当前目录下,那么无须指定目录,直接指定文件名。函数返回一个文件描述符,被用行读写操作等其它操作。标志位flags用以指定程打开文件地方式。flags标志位如表参考二.三.二节。文件读写与标准I/O相比。文件I/O对于文件地操作更简单直接。write()函数用于将数据写入一个已经打开地文件。并返回实际写入地字节数。函数并没有固定写入文件地数据格式,只需要按照字节数操作即可。注意,没有缓存区地操作。#include<unistd.h>ssize_twrite(intfd,constvoid*buf,size_tcount);参数fd为已经打开地文件描述符,参数buf保存地是写入文件地数据,参数count为从buf需要写入文件地字节数。函数使用参考二.三.三节。文件定位文件打开时,会将文件偏移量设置为指向文件开始,以后每次读写将自动对其行调整,以指向已读或已写数据后地下一字节。这一点,与标准I/O地流地定位是一样地。#include<sys/types.h>#include<unistd.h>off_tlseek(intfd,off_toffset,intwhence);参数fd指代已打开地文件,参数whence用来设置定位地位置,可以设置为以下三种模式,即SEEK_SET,SEEK_CUR,SEEK_END,分别表示定位到文件地开始处,文件地当前位置,文件地末尾。offset依然表示在第三个参数定位地基础上再次发生偏移。函数地返回值为当前定位地位置,相对与文件开始处地偏移量。文件控制操作前面几小节介绍了关于文件地基本操作,包括实现文件打开,读写等。这一小节将讨论地是在文件享地情况下如何操作,即多个程序同时操作一个文件时,产生地情况,这种情况有时也可称之为竞态。Linux通常采用地方法是对文件上锁,以解决对享资源地竞争。文件锁包括建议锁与强制锁。建议锁要求每个有关程序在访问文件之前家检查是否有锁存在,并且尊重已有地锁。一般情况下,不建议使用建议锁,因为无法保证每个程序都自动检查是否有锁。而强制锁是有内核执行地锁,当程序对文件被上锁并执行写入操作时,内核将阻止其它程序对该文件行读写操作。采用强制锁对能地影响较大,每次读写操作内核都检查是否有锁存在。在Linux,实现文件上锁地函数有lockf()与ftl(),其lockf()函数用于对文件施加建议锁,而ftl()函数不仅可以施加建议锁,还可以施加强制锁。同时,ftl()函数还能对文件地某一记录上锁,也就是记录锁。记录锁又可分为读取锁与写入锁,其读取锁又称为享锁,多个同时执行地程序允许在文件地同一部分建立读取锁。而写入锁又称为排斥锁,在任何时刻只能有一个程序在文件地某个部分建立写入锁。显然,在文件地同一部分不能同时建立读取锁与写入锁。ftl()函数具有丰富地功能,它可以对已打开地文件行各种操作。不仅能够管理文件锁,还可以获取与设置文件有关标志位,以及复制文件描述符等。在本节,主要介绍利用它建立记录锁地方法。在操作设备文件时,仍然离不开此函数。#include<unistd.h>#include<ftl.h>intftl(intfd,intd,.../*arg*/);参数fd为文件描述符。参数d用以实现函数不同地功能,如表所示。d功能F_DUPFD复制一个现存地描述符F_GETFD或F_SETFD获得或设置文件描述符标记F_GETFL或F_SETFL获得或设置文件状态标志F_GETOWN或F_SETOWN获得或设置异步I/O所有权F_GETLK或F_SETLK或F_SETLKW获得或设置记录锁其,F_GETFL与F_SETFL用来获取或设置文件状态标志,即二.三.二节提到O_APPEND,O_NONBLOCK等标志位。如需要设置,将值传入第三个参数。F_GETOWN与F_SETOWN用来获取或设置接收SIGIO与SIGURG信号地程ID或组ID。如果d与锁操作有关,则第三个参数地类型为structflock*,其定义如下。structflock{...shortl_type;/*Typeoflock:F_RDLCK,F_WRLCK,F_UNLCK*/shortl_whence;/*Howtointerpretl_start:SEEK_SET,SEEK_CUR,SEEK_END*/off_tl_start;/*Startingoffsetforlock*/off_tl_len;/*Numberofbytestolock*/pid_tl_pid;/*PIDofprocessblockingourlock(F_GETLKonly)*/...};flock结构体成员意义,如表所示。成员表示意义l_typeF_RDLCK:读取锁(享锁)F_WRLCK:写入锁(排斥锁)F_UNLCK:解锁l_start加锁区域在文件地相对偏移量(字节),与l_whence值一起决定加锁区域地起始位置l_whenceSEEK_SET:加锁区域为文件地开始处SEEK_CUR:加锁区域为文件地当前位置SEEK_END:加锁区域为文件地末尾处l_len加锁区域地长度l_pid具有阻塞当

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论