嵌入式Linux应用开发教程华清远见嵌入式学院赵苍明穆煜第五章嵌入式文件IO编程新

上传人:无*** 文档编号:127605156 上传时间:2022-07-30 格式:PPT 页数:79 大小:4.39MB
返回 下载 相关 举报
嵌入式Linux应用开发教程华清远见嵌入式学院赵苍明穆煜第五章嵌入式文件IO编程新_第1页
第1页 / 共79页
嵌入式Linux应用开发教程华清远见嵌入式学院赵苍明穆煜第五章嵌入式文件IO编程新_第2页
第2页 / 共79页
嵌入式Linux应用开发教程华清远见嵌入式学院赵苍明穆煜第五章嵌入式文件IO编程新_第3页
第3页 / 共79页
点击查看更多>>
资源描述
嵌入式应用程序设计嵌入式应用程序设计第五章 嵌入式文件I/O编程2022-7-302 5.1 Linux系统调用及用户编程接口5.2 Linux文件I/O系统概述5.3 底层文件I/O操作5.4 嵌入式Linux串口应用编程5.5 标准I/O编程5.6 实验内容5.7 小结5.8 思考与练习本章课程:本章课程:2022-7-3035.1 Linux系统调用及用户编程接口5.1.1 系统调用5.1.2 用户编程接口5.1.3 系统命令2022-7-3045.1.1 系统调用 系统调用是指操作系统提供给用户程序调用的一组“特殊”接口,用户程序可以通过这组“特殊”接口获得操作系统内核提供的服务。例如用户可以通过进程控制相关的系统调用来创建进程、实现进程之间的通信等。在Linux中,为了更好地保护内核空间,将程序的运行空间分为内核空间和用户空间(也就是常称的内核态和用户态),它们分别运行在不同的级别上,逻辑上是相互隔离的。因此,用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间的函数。但是,在有些情况下,用户空间的进程需要获得一定的系统服务(调用内核空间程序),这时操作系统就必须利用系统提供给用户的“特殊接口”系统调用规定用户进程进入内核空间的具体位置。进行系统调用时,程序运行空间需要从用户空间进入内核空间,处理完后再返回到用户空间。2022-7-305 5.1.2 用户编程接口在Linux中,用户编程接口(API)遵循了在Unix中最流行的应用编程界面标准POSIX标准。POSIX标准是由IEEE和ISO/IEC共同开发的标准系统。该标准基于当时现有的Unix实践和经验,描述了操作系统的系统调用编程接口(实际上就是API),用于保证应用程序可以在源代码一级上在多种操作系统上移植运行。这些系统调用编程接口主要是通过C库(libc)实现的。2022-7-306 5.1.3 系统命令系统命令相对API更高了一层,它实际上一个可执行程序,它的内部引用了用户编程接口(API)来实现相应的功能,它们之间的关系如图:2022-7-307 5.2 Linux文件I/O系统概述5.2.1 虚拟文件系统5.2.2 通用文件模型 5.2.3 Linux中文件及文件描述符2022-7-3085.2.1 虚拟文件系统Linux系统成功的关键因素之一就是具有与其他操作系统和谐共存的能力。Linux的文件系统由两层结构构建。第一层是虚拟文件系统(VFS),第二层是各种不同的具体的文件系统。VFS在linux系统中的位置如图:2022-7-3095.2.2 通用文件模型 通用的文件模型(common file model),这个模型的核心是4个对象类型,即超级块对象(superblock object)、索引节点对象(inode object)、文件对象(file object)和目录项对象(dentry object)。2022-7-30105.2.3 Linux中文件及文件描述符 对于Linux而言,所有对设备和文件的操作都是使用文件描述符来进行的。文件描述符是一个非负的整数,它是一个索引值,并指向在内核中每个进程打开文件的记录表。当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符;当需要读写文件时,也需要把文件描述符作为参数传递给相应的函数。一个进程启动时,都会打开3个文件:标准输入、标准输出和标准出错处理 文件描述符宏标准输入0STDIN_FILENO 标准输出1STDOUT_FILENO 标准出错2STDERR_FILENO 2022-7-30115.3 底层文件I/O操作5.3.1 基本文件操作5.3.2 文件锁5.3.3 多路复用2022-7-3012 5.3.1 基本文件操作open函数是用于打开或创建文件,在打开或创建文件时可以指定文件的属性及用户的权限等各种参数。所需头文件:#include#include#include 原型:int open(const char*pathname,int flags,int perms)2022-7-30135.3.1 基本文件操作open函数语法要点2022-7-30145.3.1 基本文件操作close()函数是用于关闭一个被打开的文件。close函数语法要点:2022-7-30155.3.1 基本文件操作read()函数是用于将从指定的文件描述符中读出的数据放到缓存区中,并返回实际读入的字节数。read函数语法要点:2022-7-3016 5.3.1 基本文件操作write()函数是用于向打开的文件写数据,写操作从文件的当前指针位置开始。write函数语法要点:2022-7-30175.3.1 基本文件操作lseek()函数是用于在指定的文件描述符中将文件指针定位到相应的位置。lseek函数语法要点:2022-7-30185.3.2 文件锁文件锁包括建议性锁和强制性锁。建议性锁要求每个上锁文件的进程都要检查是否有锁存在,并且尊重已有的锁。在一般情况下,内核和系统都不使用建议性锁。强制性锁是由内核执行的锁,当一个文件被上锁进行写入操作的时候,内核将阻止其他任何文件对其进行读写操作。采用强制性锁对性能的影响很大,每次读写操作都必须检查是否有锁存在。在Linux中,实现文件上锁的函数有lockf()和fcntl(),其中lockf()用于对文件施加建议性锁,而fcntl()不仅可以施加建议性锁,还可以施加强制锁。同时,fcntl()还能对文件的某一记录上锁,也就是记录锁。记录锁又可分为读取锁和写入锁,其中读取锁又称为共享锁,它能够使多个进程都能在文件的同一部分建立读取锁。而写入锁又称为排斥锁,在任何时刻只能有一个进程在文件的某个部分上建立写入锁。当然,在文件的同一部分不能同时建立读取锁和写入锁。fcntl()函数具有很丰富的功能,它可以对已打开的文件描述符进行各种操作,不仅包括管理文件锁,还包括获得设置文件描述符和文件描述符标志、文件描述符的复制等很多功能。2022-7-30195.3.2 文件锁fcntl()函数语法要点 2022-7-3020 5.3.2 文件锁fcntl()函数第三个参数lock说明lock为结构体flock它的定义为:struct flock flock成员取值含义如表:short l_type;off_t l_start;short l_whence;off_t l_len;pid_t l_pid;2022-7-3021 5.3.3 多路复用I/O处理模型阻塞I/O模型 非阻塞模型 I/O多路转接模型 信号驱动I/O模型 异步I/O模型 select和poll的I/O转接模型是处理I/O复用的一个高效的方法 2022-7-3022 5.3.3 多路复用select()函数的语法格式:2022-7-3023 5.3.3 多路复用select()对文件描述符进行了分类处理,处理涉及4个宏:2022-7-30245.3.3 多路复用 poll函数语法格式:2022-7-30255.4 嵌入式Linux串口应用编程5.4.1 串口概述5.4.2 串口配置详解5.4.3 串口使用详解2022-7-3026 5.4.1 串口概述常见的数据通信的基本方式可分为并行通信与串行通信两种。并行通信是指利用多条数据传输线将一个字数据的各比特位同时传送。它的特点是传输速度快,适用于传输距离短且传输速度较高的通信。串行通信是指利用一条传输线将数据以比特位为单位顺序传送。特点是通信线路简单,利用简单的线缆就可实现通信,降低成本,适用于传输距离长且传输速度较慢的通信。2022-7-30275.4.1 串口概述串口是计算机一种常用的接口,常用的串口有RS-535-C接口。DB9串口接口:2022-7-30285.4.2 串口配置详解串口设置主要是设置struct termios结构体的各个成员#include struct termios unsigned short c_iflag;/*输入模式标志*/unsigned short c_oflag;/*输出模式标志*/unsigned short c_cflag;/*控制模式标志*/unsigned short c_lflag;/*本地模式标志*/unsigned char c_line;/*线路规程*/unsigned char c_ccNCC;/*控制特性*/speed_t c_ispeed;/*输入速度*/speed_t c_ospeed;/*输出速度*/;2022-7-30295.4.2 串口配置详解 保存原先串口设置为了安全起见和以后调试程序方便,可以先保存原先串口的配置,在这里可以使用函数tcgetattr(fd,&old_cfg)。该函数得到由fd指向的终端的配置参数,并将它们保存于termios结构变量old_cfg中。该函数还可以测试配置是否正确、该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1示例:if (tcgetattr(fd,&old_cfg)!=0)perror(tcgetattr);return-1;2022-7-30305.4.2 串口配置详解 激活选项CLOCAL和CREAD分别用于本地连接和接受使能,因此,首先要通过位掩码的方式激活这两个选项。newtio.c_cflag|=CLOCAL|CREAD;调用cfmakeraw()函数可以将终端设置为原始模式,在后面的实例中,采用原始模式进行串口数据通信。cfmakeraw(&new_cfg);2022-7-30315.4.2 串口配置详解 设置波特率设置波特率有专门的函数,用户不能直接通过位掩码来操作。设置波特率的主要函数有:cfsetispeed()和cfsetospeed()。示例:cfsetispeed(&new_cfg,B115500);cfsetospeed(&new_cfg,B115500);2022-7-30325.4.2 串口配置详解 设置字符大小与设置波特率不同,设置字符大小并没有现成可用的函数,需要用位掩码。一般首先去除数据位中的位掩码,再重新按要求设置示例:new_cfg.c_cflag&=CSIZE;/*用数据位掩码清空数据位设置*/new_cfg.c_cflag|=CS8;2022-7-30335.4.2 串口配置详解 设置奇偶校验位设置奇偶校验位需要用到termios中的两个成员:c_cflag和c_iflag。首先要激活c_cflag中的校验位使能标志PARENB和是否要进行校验,这样会对输出数据产生校验位,而输入数据进行校验检查。同时还要激活c_iflag中的对于输入数据的奇偶校验使能(INPCK)。示例:奇校验new_cfg.c_cflag|=(PARODD|PARENB);new_cfg.c_iflag|=INPCK;偶校验new_cfg.c_cflag|=PARENB;new_cfg.c_cflag&=PARODD;new_cfg.c_iflag|=INPCK;2022-7-30345.4.2 串口配置详解 设置停止位设置停止位是通过激活c_cflag中的CSTOPB而实现的。若停止位为一个,则清除CSTOPB,若停止位为两个,则激活CSTOPB。示例:new_cfg.c_cflag&=CSTOPB;/*将停止位设置为一个比特*/new_cfg.c_cflag|=CSTOPB;/*将停止位设置为两个比特*/2022-7-30355.4.2 串口配置详解 设置最少字符和等待时间在对接收字符和等待时间没有特别要求的情况下,可以将其设置为0,则在任何情况下read()函数立即返回,此时串口操作会设置为非阻塞方式。示例:new_cfg.c_ccVTIME =0;new_cfg.c_ccVMIN=0;2022-7-30365.4.2 串口配置详解 清除串口缓冲由于串口在重新设置之后,需要对当前的串口设备进行适当的处理,这时就可调用在中声明的tcdrain()、tcflow()、tcflush()等函数来处理目前串口缓冲中的数据。原型:int tcflush(int fd,int queue_selector);/*用于清空输入/输出缓冲区*/tcflush()函数,对于在缓冲区中的尚未传输的数据,或者收到的但是尚未读取的数据,其处理方法取决于queue_selector的值,它可能的取值有以下几种。TCIFLUSH:对接收到而未被读取的数据进行清空处理。TCOFLUSH:对尚未传送成功的输出数据进行清空处理。TCIOFLUSH:包括前两种功能,即对尚未处理的输入输出数据进行清空处理。示例:tcflush(fd,TCIFLUSH);2022-7-30375.4.2 串口配置详解 激活配置在完成全部串口配置之后,要激活刚才的配置并使配置生效。这里用到的函数是tcsetattr(),它的函数原型是:tcsetattr(int fd,int optional_actions,const struct termios*termios_p);其中参数termios_p是termios类型的新配置变量。参数optional_actions可能的取值有以下三种:TCSANOW:配置的修改立即生效。TCSADRAIN:配置的修改在所有写入fd的输出都传输完毕之后生效。TCSAFLUSH:所有已接受但未读入的输入都将在修改生效之前被丢弃。该函数若调用成功则返回0,若失败则返回12022-7-30385.4.3 串口使用详解 打开串口使用open函数打开串口fd=open(/dev/ttyS0,O_RDWR|O_NOCTTY|O_NDELAY);接下来可恢复串口的状态为阻塞状态,用于等待串口数据的读入,可用fcntl()函数实现,如下所示:fcntl(fd,F_SETFL,0);再接着可以测试打开的文件描述符是否连接到一个终端设备,以进一步确认串口是否正确打开,如下所示:isatty(fd);该函数调用成功则返回0,若失败则返回-1。读写串口使用read/write函数读写串口 write(fd,buff,strlen(buff);read(fd,buff,BUFFER_SIZE);2022-7-30395.5 标准I/O编程标准I/O提供流缓冲的目的是尽可能减少使用read()和write()等系统调用的数量。标准I/O提供了3种类型的缓冲存储。全缓冲:在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。对于存放在磁盘上的文件通常是由标准I/O库实施全缓冲的。标准I/O尽量多读写文件到缓冲区,当缓冲区已满或手动flush时才会进行磁盘操作。行缓冲:在这种情况下,当在输入和输出中遇到行结束符时,标准I/O库执行I/O操作。这允许我们一次输出一个字符(如fputc()函数),但只有写了一行之后才进行实际I/O操作。标准输入和标准输出就是使用行缓冲的典型例子。不带缓冲:标准I/O库不对字符进行缓冲。如果用标准I/O函数写若干字符到不带缓冲的流中,则相当于用系统调用write()函数将这些字符全写到被打开的文件上。标准出错stderr通常是不带缓存的,这就使得出错信息可以尽快显示出来,而不管它们是否含有一个行结束符。2022-7-30405.5.1 基本操作打开文件打开文件有三个标准函数,分别为:fopen()、fdopen()和freopen()。它们可以以不同的模式打开,但都返回一个指向FILE的指针,该指针指向对应的I/O流。fopen()可以指定打开文件的路径和模式 fopen函数格式:2022-7-30415.5.1 基本操作打开文件mode类似于open()函数中的flag,可以定义打开文件的访问权限等,下面为mode的各种取值:2022-7-30425.5.1 基本操作打开文件fdopen()可以指定打开的文件描述符和模式。fdopen函数格式:mode取值同fopen 2022-7-30435.5.1 基本操作打开文件freopen()除可指定打开的文件、模式外,还可指定特定的I/O流。freopen函数格式:mode取值同fopen 2022-7-30445.5.1 基本操作关闭文件关闭标准流文件的函数为fclose(),该函数将缓冲区内的数据全部写入到文件中,并释放系统所提供的文件资源。fclose()函数格式:2022-7-30455.5.1 基本操作读文件在文件流被打开之后,可对文件流进行读写等操作,其中读操作的函数为fread()。fread()函数格式:2022-7-30465.5.1 基本操作写文件fwrite()函数是用于对指定的文件流进行写操作。fwrite()函数格式:2022-7-30475.5.2 其他操作字符输入/输出字符输入函数:字符输出函数:2022-7-30485.5.2 其他操作行输入/输出行输入函数:行输出函数:2022-7-3049 5.5.2 其他操作格式化输入/输出格式化输入函数:2022-7-30505.5.2 其他操作格式化输入/输出格式化输出函数:2022-7-3051 5.6 实验内容文件的读写与上锁实验目的通过编写文件读写及上锁的程序,进一步熟悉Linux中文件I/O相关的应用开发,并且熟练掌握open()、read()、write()、fcntl()等函数的使用。实验内容在Linux中FIFO是一种进程之间的管道通信机制。Linux支持完整的FIFO通信机制。本实验内容比较有趣,我们通过使用文件操作,仿真FIFO(先进先出)结构以及生产者-消费者运行模型。本实验中需要打开两个虚拟终端,分别运行生产者程序(producer)和消费者程序(customer)。此时两个进程同时对同一个文件进行读写操作。因为这个文件是临界资源,所以可以使用文件锁机制来保证两个进程对文件的访问都是原子操作。先启动生产者进程,它负责创建仿真FIFO结构的文件(其实是一个普通文件)并投入生产,就是按照给定的时间间隔,向FIFO文件写入自动生成的字符(在程序中用宏定义选择使用数字还是使用英文字符),生产周期以及要生产的资源数通过参数传递给进程(默认生产周期为1秒,要生产的资源总数为10个字符,显然默认生产总时间为10秒钟)。后启动的消费者进程按照给定的数目进行消费,首先从文件中读取相应数目的字符并在屏幕上显示,然后从文件中删除刚才消费过的数据。为了仿真FIFO结构,此时需要使用两次拷贝来实现文件内容的偏移。每次消费的资源数通过参数传递给进程,默认值为10个字符。2022-7-30525.6 实验内容文件的读写与上锁2022-7-30535.6 实验内容 多路复用式串口操作实验目的通过编写多路复用串口读写,进一步理解多路复用函数的用法,同时更加熟练掌握Linux设备文件的读写方法。实验内容本实验中,实现两台机器(宿主机和目标板)之间的串口通信,而且每台机器均可以发送和接收数据。除了串口设备名称不同(宿主机上使用串口1:/dev/ttyS0,而在目标板上使用串口5:/dev/ttyS1),两台机器上的程序基本相同。首先程序打开串口设备文件并进行相关配置。调用select()函数,使它等待从标准输入(终端)文件中的输入以及从串口设备的输入。如果有标准输入上的数据,则写入到串口,使对方读取。如果有串口设备上的输入,则将数据写入到普通文件中。2022-7-30545.6 实验内容多路复用式串口操作开始打开并设置串口select等待(终端/串口)从终端输入数据结束从串口读入数据读取quit?将读取的数据写入到普通文件中将读取的数据写入到串口否是图5.5 宿主机/目标板程序的流程图2022-7-30555.7 小结 1.本章首先讲解了系统调用、用户函数接口和系统命令之间的联系和区别以及Linux的文件系统的基本知识。2.接着,本章重点讲解了嵌入式Linux中文件I/O开发相关的内容,在这里主要讲解了不带缓存的I/O系统调用函数的使用,这也是本章的重点。因为不带缓存I/O函数的使用范围非常广泛,在很多情况下必须使用它,这也是学习嵌入式Linux开发的基础,因此读者一定要牢牢掌握相关知识。其中讲解了基本文件操作、文件锁和多路复用等操作,这些函数包括了不带缓存I/O处理的主要部分,并且也体现了它的主要思想。3.接下来,本章讲解了嵌入式Linux串口编程。这也是嵌入式Linux中设备文件读写的实例,由于它能很好地体现前面所介绍的内容,而且在嵌入式开发中也较为常见,因此对它进行了比较详细地讲解。4.在本章的后面,简单介绍了标准I/O的相关函数,希望读者也能对它有一个总体的认识。5.最后,本章安排了两个实验,分别是文件使用及上锁和多用复用串口操作。希望读者认真完成。2022-7-30565.8 思考与练习 1.简述虚拟文件系统在Linux系统中的位置和通用文件系统模型。2.底层文件操作和标准文件操作之间有哪些区别?3.比较select()函数和poll()函数。然后使用多路复用函数实现3个串口的通信:串口1接收数据,串口5和串口3向串口1发送数据。2022-7-3057572022-7-3058在线教务辅导网:在线教务辅导网:http:/ 更多课程配套课件资源请访问在线教务辅导网更多课程配套课件资源请访问在线教务辅导网2022-7-30592022-7-30602022-7-30612022-7-30622022-7-30632022-7-3064馋死2022-7-30652022-7-30662022-7-30672022-7-30682022-7-30692022-7-30702022-7-30712022-7-30722022-7-30732022-7-30742022-7-30752022-7-30762022-7-3077PPT研究院P O W E R P O I N T A C A D E M Y2022-7-30782022-7-3079
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 压缩资料 > 基础医学


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!