《第8章Linux系统应用程序开发基础.pptx》由会员分享,可在线阅读,更多相关《第8章Linux系统应用程序开发基础.pptx(48页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、嵌入式系统原理与开发教程Linux系统应用程序开发基础主讲人:赖树明东莞理工学院01Linux系统程序设计基础03Linux系统Makefile使用04Linux文件IO编程05课程作业任务02Linux静态库和动态库0101Linux系统程序设计基础Linux程序设计概述GCC 编译器学习Linux系统标准main函数Linux系统程序设计基础 Linux程序设计概述01在Windows系统中,开发工具多以集成开发环境IDE的形式展现给最终用户。例如,VS2019集成了编辑器,宏汇编ml,C/C+编译器cl,资源编译器rc,调试器,文档生成工具,nmake。在Linux系统中,开发工具被切割
2、成一个个独立的小工具,各自处理不同的问题。l编辑器(emacs,vim,gedit)用来进行编辑程序l调试器(gdb)用来调试程序l编译器(GCC)用来编译和链接程序本节重点讲解GCC使用方法,这是踏入Linux编程世界的第一步,要求必须掌握。Linux历史Linux程序设计概述Linux系统程序设计基础 GCC编译器01GNU是一个计划或者叫运动,在GNU计划开发了很多的工作和项目,包括核心的gcc和glibc。Linux系统下的gcc(GNUCCompiler)是GNU推出的功能强大、性能优越的多平台编译器。gcc是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器
3、相比平均效率要高20%30%。gcc编译器能将C、C+语言源程序、汇程式化序和目标程序编译、连接成可执行文件。在Linux系统中,可执行文件没有统一的后缀,系统从文件的属性来区分可执行文件和不可执行文件。而gcc则通过后缀来区别输入文件的类别。Linux历史GCC编译器介绍Linux系统程序设计基础 GCC编译器学习01.c为后缀的文件,C语言源代码文件;.a为后缀的文件,是由目标文件构成的档案库文件;.C或.cc或.cxx为后缀的文件,是C+源代码文件;.h为后缀的文件,是程序所包含的头文件;.i为后缀的文件,是已经预处理过的C源代码文件;.ii为后缀的文件,是已经预处理过的C+源代码文件;
4、.m为后缀的文件,是Objective-C源代码文件;.o为后缀的文件,是编译后的目标文件;.s为后缀的文件,是汇编语言源代码文件;.S为后缀的文件,是经过预编译的汇编语言源代码文件。Linux历史GCC支持的文件扩展名Linux系统程序设计基础 GCC编译器学习01C语言从源代码到可执行文件需要经历四个相互关联的步骤,如下所示:GCC编译程序流程预处理(Preprocessing)源代码文件中以#开头的代码进行处理,如#include,#define,#if等),生成不带#开头代码的源中间文件编译(Compilation)把预处理的文件编译生成以.s为后缀的汇编代码文件。汇编(Assembl
5、y)把上一步得到的汇编文件使用汇编器进行编译,生成以.o为后缀的二进制目标文件,但是这时的文件还不能执行。链接(Linking)把所有的.o文件使用链接器进行链接,整合成一个可执行程序。Linux系统程序设计基础 GCC编译器学习01gcc常用选项选项含义-c只编译不链接,源文件编译成目标代码(.o),默认生成目标文件“.o”-S(注意是大写S)生成汇编代码-E只进行预编译,不做其他处理-g在可执行程序中包含标准调试信息-o指定输出文件名-O代码优化选项,-ON:指定优化级别,0=N=3,默认为1-v打印出编译内部编译各过程的命令行信息和编译器的版本-Wall打开所有警告-Werror把所有警
6、告当成错误处理-w关闭所有警告-static链接静态库,默认情况下gcc只链接动态库(静态库:以.a为扩展名,动态库:带.so扩展名的库文件)静态链接:生成的可执行程序包含所有调用的函数实现代码动态链接:生成的可执行程序是运行时才在so动态库中搜索其调用的函数的。-I指定编译时包含的头文件路径-L指定链接时第三库文件的路径-l(L的小字字母)指定链接时库文件的名称 在Linux系统中库文件命名 lib库名库名.so*或lib库名库名.a,指定库:-l库名库名 Linux系统程序设计基础 GCC编译器学习01main.c源码清单:#includeexternintadd(int,int);ext
7、ernintsub(int,int);intmain(void)printf(“1+2:%drn,add(1,2);printf(“20-10:%drn,sub(20,10);gcc编译示例add.c源码清单:intadd(inta,intb)returna+b;sub.c源码清单:intsub(inta,intb)returna-b;编译过程:分别编译三个文件为二进制目标文件gcc-Emain.c-omain.igcc-Smain.i-omain.sgcc-cmain.s-omain.ogcc-Eadd.c-oadd.igcc-Sadd.i-oadd.sgcc-cadd.s-oadd.ogc
8、c-Esub.c-osub.igcc-Ssub.i-osub.sgcc-csub.s-osub.o链接:gccmain.osub.oadd.o-omain运行:./maingcc编译器也支持一次编译生成可执行程序,如上面三个c程序,执行以下指令:gcc main.c sub.c add.c-o main 可以直接生成可执行程序main。Linux系统程序设计基础 Linux标准main函数01在Linux系统或Windows系统中,启动应用程序时可以给程序传递参数,例如:“ls-l/home”中,“ls”是程序名,“-l”是参数1,“/home”是参数2,如有更多依次类推。程序要接收启动的参数
9、,由需要通过main函数来完成。示例:以下app-arg.c把命令行中输入的参数数量及每个参数全部输出。app-arg.c源码清单:#includeintmain(intargc,char*argv)inti=0;printf(argc:%drn,argc);for(i=0;iargc;i+)printf(argv%d:%srn,i,argvi);系统级标准main函数说明:uargc记录了启动程序时参数个数,程序名本身算一个参数;uargv是一个char*类型的数组,每个元素保存了命令行为每个字符串参数地址,通过argv的下标可以取得启动程序时传递给程序的参数。编译:$gccapp-arg.
10、c-oapp-arg运行测试:$./app-argc:4argv0:./app-argargv1:xydargv2:123argv3:结果分析:以空格分隔的,每个字符串是一个参数,分别保存在argv数组中。0202Linux静态库和动态库静态库和动态库相关编译选项静态库的创建及使动态库的创建及使动态库与静态库的比较Linux静态库和动态库概述02函数库是能提供一系列功能函数给第三方程序调用的文件,可分为静态库和动态库(也称为共享库),在使用上对应静态链接和动态链接。编译链接程序时,链接器会根据命令选项采用动态库还是静态库中的函数。函数库定义动态库命名:lib.so.y.zlib:固定名称前缀;
11、so:固定后缀y:次版本号;z:发行版本号,其中.y.z是可选的静态库命名:lib.a库命名规则把功能函数写到单独的C文件中,使用编译器封装成.a文件,第三方程序要调用其中的函数时通过编译选项-static-l库名 形式把调用的函数对应代码复制一份到当前程序中,运行时候就再依赖静态库文件。静态库使用原理把功能函数写到单独的C文件中,使用编译器封装成lib.so.y.z动态库文件,第三方程序要调用其中的函数时通过编译选项 -l库名 形式来找到库,记录函数符号,并没有复制代码到当前程序中,而是运行时才加载动态库文件到,找到函数执行。动态库使用原理Linux静态库和动态库静态库和动态库相关编译选项0
12、2如果gcc编译命令中指定该选项,表示代码中使用到来自第三方库的函数必须存在静态库,不能是动态库,否则链接失败。-static选项如果gcc编译指令中指定该选项,表示优先使用动态库链接,即代码中使用来自第三方库的函数,如果同时存在动态库和静态库,会优先使用动态库链接,如果只存在静态库,才会使用静态库文件链接。-shared选项如果gcc编译指令中指定该选项,表示要生成相对地址位置无关的目标代码,通常使用gcc的-shared选项把生成位置无关目标文件编译成动态库文件。-fPIC选项在使用第三方库时,如果没有把第三方库文件复制到系统存放库文件的标准路径中,则要在编译阶段使用-L选项来指定第三方库
13、的存放位置。而-I后面跟着的是库文件存放路径,后面可以加空格,也可以不加空格直接写库文件路径,路径可以是相对路径,也可以使用绝对路径。-L选项链 接 时,采 用 链 接 名 为 libname.a静 态 库 或libname.so动态库的库文件或其中的一个。若两个库文件都存在,则根据编译时指定的选项(-static或-shared或不写)来进行链接。-lname选项aad.c :aad.c :intadd(inta,intb)intc;c=a+b;returnc;Linux静态库和动态库03编写功能函数静态库的创建及使用sub.c :sub.c :intsub(inta,intb)intc;c
14、=a-b;returnc;aad.h :aad.h :#ifndef_ADD_H_#define_ADD_H_intadd(inta,intb);#endifsub.h :sub.h :#ifndef_SUB_H_#define_SUB_H_intsub(inta,intb);#endif gcc-c add.c-o add.o gcc-c add.c-o add.o gcc-c sub.c-o sub.o gcc-c sub.c-o sub.o编译函数为.o文件 ar-crsv libfunction.a add.o sub.o ar-crsv libfunction.a add.o sub
15、.o把.o文件封装成.a执执行行上上面面命命令令后后会会生生成成libfunction.alibfunction.a静静态态库库文文件件,后后面面就就可可以以供供第第三三方方程程序使用。序使用。main.c:main.c:#include#include#includeadd.h/#includeadd.h/引入函数声明引入函数声明#includesub.h#includesub.h/引入函数声明引入函数声明intmain(void)intmain(void)printf(2+1=%d;rn2-1=%drn,add(2,1),sub(2,1);printf(2+1=%d;rn2-1=%drn,
16、add(2,1),sub(2,1);return0;return0;Linux静态库和动态库03测试代码编写静态库的创建及使用工程文件存放结构 include include add.h add.h sub.h sub.h src src add.c add.c libfunction.a main.c main.c sub.c sub.c说明:编译为说明:编译为.a.a 文件后,可以把文件后,可以把add.cadd.c、sub.csub.c删除,我们只需要删除,我们只需要.a.a文件即可。文件即可。编译:编译:gcc-o main main.c gcc-o main main.c libfu
17、nction.a-I./include/-I./include/-这种是把库当成源文件一样使用或者:或者:gcc-o main main.c-I./include gcc-o main main.c-I./include-L./-lfunction -这种是标准的使用方法编编译译生生成成mainmain可可执执行行程程序序后后可可以以删删除除.a.a文文件件,不不会会影影响响到到后后面面可可执执行行程程序序的的运运行行,因因为它已复制一份代码到其中。为它已复制一份代码到其中。运行:运行:./main./mainaad.c :aad.c :intadd(inta,intb)intc;c=a+b;
18、returnc;Linux静态库和动态库03编写功能函数态库的创建及使用sub.c :sub.c :intsub(inta,intb)intc;c=a-b;returnc;aad.h :aad.h :#ifndef_ADD_H_#define_ADD_H_intadd(inta,intb);#endifsub.h :sub.h :#ifndef_SUB_H_#define_SUB_H_intsub(inta,intb);#endif gcc-fPIC-c add.c gcc-fPIC-c add.c-o add.o-o add.o gcc gcc-fPIC -fPIC -c sub.c-o s
19、ub.o-c sub.c-o sub.o编译函数为.o文件gcc-o libfunction.so-shared add.o sub.ogcc-o libfunction.so-shared add.o sub.o把.o文件封装成.a执执行行上上面面命命令令后后会会生生成成libfunction.so libfunction.so 动动态态库库文文件件,后面就可以供第三方程序使用。,后面就可以供第三方程序使用。补充:也支持把上三条指令合并成为条:补充:也支持把上三条指令合并成为条:gcc-o libfunction.so-shared gcc-o libfunction.so-shared-f
20、PIC add.c sub.c add.c sub.cmain.c:main.c:#include#include#includeadd.h/#includeadd.h/引入函数声明引入函数声明#includesub.h#includesub.h/引入函数声明引入函数声明intmain(void)intmain(void)printf(2+1=%d;rn2-1=%drn,add(2,1),sub(2,1);printf(2+1=%d;rn2-1=%drn,add(2,1),sub(2,1);return0;return0;Linux静态库和动态库03测试代码编写态库的创建及使用工程文件存放结构
21、 include include add.h add.h sub.h sub.h src src add.c add.c libfunction.so main.c main.c sub.c sub.c说明:编译为说明:编译为.so.so 文件后,可以把文件后,可以把 add.cadd.c、sub.csub.c删除,我们只需要删除,我们只需要 .so so 文件即可。文件即可。编译:编译:gcc-o main main.c gcc-o main main.c libfunction.so-I./include/-I./include/-这种是把库当成源文件一样使用或者:或者:gcc-o mai
22、n main.c-I./include gcc-o main main.c-I./include-L./-lfunction -这种是标准的使用方法编编译译生生成成mainmain可可执执行行程程序序后后可可以以删删除除.a.a文文件件,不不会会影影响响到到后后面面可可执执行行程程序序的的运运行行,因因为它已复制一份代码到其中。为它已复制一份代码到其中。运行:运行:./main./mainLinux静态库和动态库03运行测试程序态库的创建及使用由由于于采采用用动动态态库库,生生成成mainmain可可执执行行程程序序在在链链接接时时并并没没有有把把调调用用的的add,subadd,sub函函数
23、数实实现现代代码码复复制制到到程程序序当当中中,而而在在运运行行时时候候在在系系统统库库环环境境变变量量中中指指定定的的路路径径去去搜搜索索动动态态库库文文件件,加加载载到到内内在在中中,然然后后再再调调用用已已经经加加载载到到内内在在的的soso文文件件中中的的函函数数代代码码,因因此此,要要想想正正确确运运行行使使用用了了动动态态库库的的程程序序,必必须须把把依依赖赖的的动动态态库库也也复复制制到到系系统统的的环环境境变变量量指指定定的的目目标标当当中中,一一般般可可以以复复制制到到/lib/lib目目录录即即可可,当当然然其其他他系系统统环环境境变变量量指定的库存放目录也是可以的。指定的
24、库存放目录也是可以的。复制动态库文件到复制动态库文件到/lib /lib 目录中:目录中:sudo cp libfunction.a/lib/sudo cp libfunction.a/lib/运行测试程序:运行测试程序:./main./main 补补充充:如如果果不不复复制制到到系系统统环环境境变变量量指指定定的的库库路路径径,也也可可以以通通过过临临时时导导出出环环境境变变量量的的方方式式,不不过过不不推推荐荐使用这种,每次都需要操作一次,比较麻烦:使用这种,每次都需要操作一次,比较麻烦:exportLD_LIBRARY_PATH=$PWDexportLD_LIBRARY_PATH=$PW
25、D。另一种方法:修改另一种方法:修改/etc/ld.so.conf/etc/ld.so.conf配置文件配置文件,把动态库文件所在路径写到其中,然后,把动态库文件所在路径写到其中,然后 执行执行“sudoldconfig”“sudoldconfig”命令让系统重新加载命令让系统重新加载/etc/ld.so.conf/etc/ld.so.conf配置文件可,系统会到指定路径加载动态库配置文件可,系统会到指定路径加载动态库。0303Linux系统Makefile使用Makefile概述Makefile语法Makefile编程进阶少量代码可以直接使用:gcc源代码列表-o可执行程序名命令直接编译,如
26、果文件数量庞大,每次都使用上面命令编译则会耗费大量时间(输入命令、哪怕是没有修改地的文件都重新编译都需要花费时间)Linux中使用makefile来解决文件编译的问题,Makefile中定义了一系列的规则,指定哪文件的编译顺序,哪些文件需要重新编译,或实现更复杂的功能操作。Makefile就像一个Shell脚本一样,Makefile文件中也使用Linux系统的命令。Makefile可以实现自动化编译”,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。使用make命令来是解释Makefile编写的编译规则。Makefile使用:把命令终端工作目录切换到包含编写好的Mak
27、efile的目录,输入make命令即可。Linux系统Makefile使用03概述Makefile概述目标1:依赖1依赖2依赖3TAB键所有依赖都实现后会执行的命令语句1TAB键所有依赖都实现后会执行的命令语句2依赖1:依赖1TAB键所有依赖都实现后会执行的命令语句1目标2:依赖1依赖2依赖3TAB键所有依赖都实现后会执行的命令语句1Linux系统Makefile使用03Makefile文件格式Makefile语法Makefile中的目标名,根据需要随意定义;目标名一般是对应于硬盘上的一个同名文件,目标规则下方的命令语句必须以tab键开头,命令语句可根据需要编写,可以使用Linux各种命令依赖
28、可以是一个文件,也可以是Makefile中一个目标规则;命令终端输入make 命令后,make程序会在当前目录查找名为Makefile/makefile的文件,执行其中的第一个目标规则下的命令;某些操作并不需要生成文件,则PHONY关键字声明为一个伪目标;声明伪目标的语法:PHONY:目标名1目标名2如:PHONY:rebuildclean被声明为伪目标的目的规则名make程序不会视为文件,不会关心硬盘上是否存在这个文件,而是无条件执行目标名下对应的命令;main:main.oadd.ogcc-omainmain.oadd.omain.o:main.cgcc-cmain.cadd.o:add.
29、cgcc-cadd.c#把clean声明为伪目标PHONY:cleanclean:rm*.omainLinux系统Makefile使用03Makefile入门示例Makefile语法注意:和shell编程相同,在Makefile中,也用“#”号表示注释执行Makefile中指定目标:语法:make目标名说明:不指定目标名则默认第一个目标例如:make执行第一个目标规则下方的命令语句makeclean执行clean目标下方的命令语句makeadd.o执行add.o目标下方的命令语句make命令会根据Makefile递归推导目标规则依赖实现方法,当所有依赖实现Makefile中可以定义变量,与C语
30、言不同,没有类型说明,值全部以字符形式表示;Makefile定义变量:直接命名一个合法标识符,同时对它进行初始化Makefile变量初始化有四种方法:使用=:=+=?=+=:最普通的赋值方式;:=:变量值简单变量展开(类似于C语言赋值),是覆盖之前的值,通常采用这种形式;?=:如果当前变量没有赋值才进行赋值,这种方式一般用于可以通过make变量名=新值方式来替换Makefile中的定义的默认值;比如:makefile中定义变量var?=123,命令行输入makevar=567,则var值会被567替换;+=:追加上原来的数值,如:A+=123A+=www则结果是A值为123www变量引用:要取
31、得变量的值,使用$(变量名)或$变量名,建议使用$(变量名)Linux系统Makefile使用03使用普通变量Makefile编程进阶APP_NAME?=mainOBJS:=main.oadd.o$(APP_NAME):$(OBJS)gcc-o$(APP_NAME)$(OBJS)main.o:main.cgcc-cmain.c-omain.oadd.o:add.cgcc-cadd.c-oadd.o#声明伪目标PHONY:rebuildcleanclean:rm-rf$(APP_NAME)$(OBJS)*Linux系统Makefile使用03Makefile普通变量示例Makefile编程进阶e
32、du118localhost:02_makefile$makecleanrm-rfmainmain.oadd.o*edu118localhost:02_makefile$makegcc-cmain.c-omain.ogcc-cadd.c-oadd.ogcc-omainmain.oadd.o运行生成的可执行程序:edu118localhost:02_makefile$./mains:3hellolinux!在Makefile规范中定义了一些具有特定含义的变量,我们可以使用这些变量进一步优化Makefile,以下列出比较常用的。Linux系统Makefile使用03使用自动变量Makefile编程
33、进阶变量名说明$当前规则的目标名$当前规则的第一个依赖如main:main.oadd.o,则命令中$结果是main.o$当前规则的所有依赖文件,以空格分隔,如main:main.oadd.o,则命令中$结果是 main.oadd.o$?规则中日期新于目标文件的所有相关文件列表,逗号分隔$(D)目标文件的目录名部分,如目标名是bin/main则命令中$(D)得到bin$(F)目标文件的文件名部分,如目标名是bin/main则命令中$(F)得到main#外部可以传入新值替换这里的mainAPP_NAME?=mainOBJS:=main.oadd.o$(APP_NAME):$(OBJS)gcc-o$
34、main.o:main.cgcc-c$-o$add.o:add.cgcc-c$-o$#声明伪目标PHONY:rebuildcleanclean:rm-rf$(APP_NAME)$(OBJS)*Linux系统Makefile使用03Makefile自动变量示例Makefile编程进阶edu118localhost:02_makefile$makecleanrm-rfmainmain.oadd.o*编译:edu118localhost:02_makefile$makegcc-cmain.cgcc-cadd.cgcc-omainmain.oadd.o运行生成的可执行程序:edu118localhos
35、t:02_makefile$./mains:3hellolinux!前面使用使用变量优化的Makefile还存在很多不足的,比如每添加增加一个C文件,必须增加一个生成.o文件的规则,如下:mul.o:mul.cgcc-c$-o$Makefile规则中支持使用模式规则,所谓模式匹配规则即是通过匹配模式找字符串,你可以理解为类似命令的通配置符。Makefile中规定使用“%”匹配1或多个任意字符串。上面的mul.o:mul.c演变为:%.o:%.c,表示任意目标文件依赖文件是与目标文件同名.c的文件;Linux系统Makefile使用03模式规则%.o:%.cMakefile编程进阶#外部可以传入
36、新值替换这里的mainAPP_NAME?=mainOBJS:=main.oadd.o$(APP_NAME):$(OBJS)gcc-o$%.o:%.cgcc-c$-o$#声明伪目标PHONY:rebuildcleanclean:rm-rf$(APP_NAME)$(OBJS)*Linux系统Makefile使用03Makefile模式规则示例Makefile编程进阶edu118localhost:02_makefile$makecleanrm-rfmainmain.oadd.o*编译:edu118localhost:02_makefile$makegcc-cmain.cgcc-cadd.cgcc-
37、omainmain.oadd.o运行生成的可执行程序:edu118localhost:02_makefile$./mains:3hellolinux!#外部可以传入新值替换这里的mainAPP_NAME?=mainOBJS:=main.oadd.o$(APP_NAME):$(OBJS)gcc-o$%.o:%.cgcc-c$-o$#声明伪目标PHONY:rebuildcleanclean:rm-rf$(APP_NAME)$(OBJS)*Linux系统Makefile使用03模式规则使用示例Makefile编程进阶edu118localhost:03_makefile$makecleanrm-rf
38、mainmain.oadd.o*编译:edu118localhost:03_makefile$makegcc-cmain.cgcc-cadd.cgcc-omainmain.oadd.o运行生成的可执行程序:edu118localhost:03_makefile$./mains:3hellolinux!上面的Makefile当项目文件增加时,还需要再修改Makefile,如:修改OBJS:=main.oadd.o变量值解决:使用Makefile函数的来遍历指定目录的c文件,然后把后缀名去掉,得到目标名文件列表常用几个Makefile函数有wildcard,patsubst,addprefixLi
39、nux系统Makefile使用03Makefile函数使用Makefile编程进阶#外部可以传入新值替换这里的mainAPP_NAME?=main#得到当前目录的c文件列表SRCS:=$(wildcard*.c)#把.c替换为.o,得到.o文件列表OBJS:=$(patsubst%.c,%.o,$(SRCS)$(APP_NAME):$(OBJS)gcc-o$%.o:%.cgcc-c$-o$#声明伪目标PHONY:rebuildcleanclean:rm-rf$(APP_NAME)$(OBJS)*Makefile函数使用示例edu118localhost:04_makefile$makeclea
40、nrm-rfmainmain.oadd.o*编译:edu118localhost:04_makefile$makegcc-cmain.cgcc-cadd.cgcc-omainmain.oadd.oedu118localhost:04_makefile$makemake:mainisuptodate.运行生成的可执行程序:edu118localhost:04_makefile$./mains:3hellolinux!0404Linux文件IO编程Linux文件类型Linux文件IO分类非缓冲文件IO编程缓冲文件IO编程-选修Linux系统中一切皆文件,对普通文件和硬件设备的操作都是文件操作。Li
41、nux系统文件分为普通文件,管道文件,目录文件,链接文件,套接字文件和设备文件。普通文件:也称磁盘文件,并且能够进行随机的存储数据(能够自由seek定位到某一个位置);管道文件:是一个从一端发送数据,另一端接收数据的数据通道;目录文件:它包含了保存在目录中文件列表的简单文件。套接字文件:在Linux中,套接字也可以当作文件来进行处理。设备文件:Linux下各种硬件设备在内核中都表现为一个设备文件,通过设备文件操作对应的硬件设备。设备文件有两种类型:字符型设备和块设备。字符设备文件:是以字节为单位进行顺序读写的设备,如鼠标、键盘、终端、打印机、声卡,串口等,各类传感器;块设备文件:以块为单位来读
42、出或者写入数据,如CD-ROM、硬盘、SD卡,U盘等大容量存储类型设备;对文件操作一般步骤:打开文件,读/写/移动读写指针等操作,关闭文件。其中打开文件是第一步,是为后续操作做准备的。Linux文件IO编程 Linux文件类型04在Linux系统中,对文件进行读写操作有两套机制:缓冲文件IO操作和非缓冲文件IO操作;缓冲文件IO操作:这种文件操作就是标准C库提供的文件操作;对文件读写是带缓冲区的,一般使用来操作硬盘上的数据文件,如电影,音乐,文档等普通文件。非缓冲文件IO操作:这种文件操作就是Linux系统特有的文件操作,只能在Linux系统中使用,对文件读写的读写是不带缓冲区的,一般使用来操
43、作硬件设备在系统中的设备文件,如鼠标,键盘,传感器,UART等对应的设备文件,当然,它也可以使用来操作硬盘上的数据文件,如电影,音乐,文档。IO分类Linux文件IO编程 Linux文件IO分类04文件描述符:是内核为了高效的管理已经被打开的文件所创建的编号,它是一个非负整数,用于指代被打开的文件,所有执行I/O操作的系统调用都是通过文件描述符完成的。当某个程序打开文件时,操作系统返回相应的文件描述符,程序为处理该文件必须引用此描述符。所谓的文件描述符是一个低级的正整数。最前面的三个文件描述符(0,1,2)分别与标准输入(stdin),标准输出(stdout)和标准错误(stderr)对应。每
44、次打开的文件时(含socket)必须使用当前进程中最小可用的文件描述符号码。Linux文件IO编程 非缓冲文件IO编程04主要函数文件描述符open(打开)、read(读)、write(写)、close(关闭)、lseek(调整读写位置)Linux文件IO编程 非缓冲文件IO编程04open函数头文件:#include#include#include原型1:intopen(constchar*pathname,intflags);原型2:intopen(constchar*pathname,intflags,mode_tmode);功能:打开一个现有文件或创建一个新文件参数:pathname:
45、带路径的文件名,表示要操作哪个文件。flags:文件打开方式,常用值:O_RDONLY:只读模式O_WRONLY:只写模式O_RDWR:可读可写O_CREAT:如果文件不存在,则创建;mode:当创建新文件时设置文件访问权限的初始值,和用户掩码umask有关;返回值:=0:打开成功,值为文件描述符,这个数值关联pathname表示的文件;-1:打开失败。mode 可取值:S_IXOTH:其他用户有执行权0o001S_IWOTH:其他用户有写权限0o002S_IROTH:其他用户有读权限0o004S_IRWXO:其他用户有全部权限(权限掩码)0o007S_IXGRP:组用户有执行权限0o010S
46、_IWGRP:组用户有写权限0o020S_IRGRP:组用户有读权限0o040S_IRWXG:组用户有全部权限(权限掩码)0o070S_IXUSR:拥有者具有执行权限0o100S_IWUSR:拥有者具有写权限0o200S_IRUSR:拥有者具有读权限0o400S_IRWXU:拥有者有全部权限(权限掩码)0o700Linux文件IO编程 非缓冲文件IO编程04read函数头文件:#include原型:ssize_tread(intfd,void*buf,size_tcount);功能:从fd关联的文件中读取最多count字节数据保存到buf指向的内存首地址;参数:fd:要读取得文件描述符;buf
47、:数据指针,指向保存读取到的数据的内存地址;count:要读取的字节数量;返回值:出错:-1;0:读文件结束;0:成功读取到的字节数;0=返回值count时表示已经把文件数据读取完成;=count并不能判断已经读取完成,即使文件只count字节。注意:每读取成功1字节,文件读写位置指针增加1。write函数头文件:#include原 型ssize_t write(intfd,constvoid*buf,size_tcount);功能:把buf指向的内存开始的数据,写入到fd关联的文件中,最多写入ount字节;参数:fd:要读取得文件描述符;buf:数据指针,指向要写入的数据的内存首地址;cou
48、nt:要写入的的字节数量;返回值:-1:出错:0:成功写入到的字节数;注意:每写入成功1字节,文件读写位置指针增加1注意1:文件读写位置是共用一个读写位置指针的,每读写成功1字节,则文件读写位置相应增加1字节;注意2:读写函数调用都是从当前文件读写位置开始读写数据的;Linux文件IO编程 非缓冲文件IO编程04lseek函数头文件:#include#include原型:off_tlseek(intfd,off_toffset,intwhence);参数:fd:之前用open()获得的一个文件描述符;offset:要调整的读写偏移量,可正可负,如何由whence来确定的;whence参数分为下
49、列三种:SEEK_SET:最终的读写位置=offset。SEEK_CUR:最终的读写位置=当前读写位置+offsetSEEK_END:最终的读写位置=文件末尾+offset返回值:=0:调用成功,值含义是距离文件开头字节偏移。-1:调用失败,错误代码保存在全局变量errno中,常见的erron的错误代码:EBADF:fildes不是一个打开的文件描述符。ESPIPE:文件描述符被分配到一个管道、套接字或FIFO。EINVAL:whence取值不当。close函数头文件:#include原型:intclose(intfd);参数:fd:之前用open()获得的一个文件描述符;返回值:成功0,否则
50、返回-1,同时失败原因会被记录在errno中。常见的错误原因有:EBADF:fd不是有效的文件描述符EINTR:close()被某个信号处理程序中断EIO:关闭文件时发生了IO错误Linux文件IO编程 非缓冲文件IO编程04创建/写/读示例Linux文件IO编程 非缓冲文件IO编程04创建/写/读示例测试结果1.非缓冲文件IO使用描述符(实际上一个整数)关联一个打开的文件,而缓冲文件IO使用文件流指针FILE*来关联一个已经打开的文件;2.文件结构FILE体内部成员一般不需要关注,编程时只通过fopen得到的FILE*类型指针来进行后面的fread,fwrite,fseek,ftell,fc