版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Linux系统程序设计教程第1章Linux基础第1章Linux基础第2章Linux系统开发环境第3章Linux程序设计初步第4章文件IO第5章文件属性第6章目录文件管理第7章进程控制第8章线程第9章信号与管道第10章进程间通信第11章网络编程第12章综合案例全套可编辑PPT课件第1章Linux基础1.1Unix/Linux简介1.2库函数与系统调用1.3Linux常用命令1.4案例1:通过SSH终端登录Linux21.1Unix/Linux简介Unix概述1969年:KenThompson汇编语言1973年:与DennisRitchie用C语言重写UNIXⅢUNIX分为SystemV和BSD两大主流1978年:加利福尼亚大学伯克利分校以UNIX第六版为基础改进成BSD系列UNIX1983年:SystemV版本1发布,第一个商业UNIX版本SystemV版本4是较成功的,或称为SVR41992年,版权纠纷,伯克利分校删除原UNIX代码,重写内核,1994年诞生4.4BSD版本,成为现代BSD基本版本31.1Unix/Linux简介UNIX体系结构内核:一组软件的集合,用来控制计算机硬件资源,提供程序运行环境。系统调用:获取内核服务的接口。Shell:一个特殊的应用程序,是用户和内核之间交互的界面。库函数:构建在系统调用之上,获取一些功能的接口。应用软件:用户使用的应用程序,基于Shell、系统调用或库函数实现。41.1Unix/Linux简介Linux概述1987年:荷兰的Vrije大学的AndrewS.Tanenbaum开发MINIX,用于操作系统课程的教学。1991年:Linus学习MINIX,并发布了Linux内核。内核版本发布:2003年(2.6)、2011年(3.0)、2015年(4.0)、2019(5.0)、2022年(6.0)Linux版本的两种说法内核版本:Linux2.4.20,Linux2.6等r.x.y:r-主版本号,x-偶数稳定奇数开发,y-错误修补次数3.0版本后不再采用奇偶数代表稳定版本。发行版本:RedHatLinux9.0,SUSE10,Ubuntu24.04等厂家将Linux内核与外围实用程序和文档包装,提供安装界面和系统配置、管理工具等,形成的操作51.1Unix/Linux简介1.开放性2.多用户3.多任务4.良好的用户界面5.设备独立性6.丰富的网络功能7.可靠的系统安全8.良好的可移植性61.2库函数与系统调用系统调用操作系统提供给外部程序的接口。库函数C语言库函数提供给C语言编程需要的功能,有的库函数需要调用系统调用接口。Linux中有GNU的glibc,POSIX的线程函数库等。从用户角度观察都以常见的C语言函数形式出现,调用方法一致。从实现者角度观察调用库函数有的需要内核的服务,有的不需要,需要内核服务的库函数是要调用系统调用的。------用户态调用系统调用后执行内核程序。------核心态71.3Linux常用命令用户和用户组useraddpasswduserdelgroupaddgroupdel81.3Linux常用命令文件和目录mkdirmvcprmchgrpchown91.3Linux常用命令进程pskill获取帮助信息man10案例1:通过SSH终端登录Linux分析及设计本项目要求在Windows中远程访问虚拟机中的Linux系统,使用命令创建本书中所需的各章节目录,然后将这些目录下载到Windows的某个文件夹中。方式1:WSL方式2:虚拟机11案例1:通过SSH终端登录Linux实施和运行Linux系统作为服务器,安装OpenSSH软件Windows作为客户机,安装终端访问软件,如XShell或者安装VSCode。Windows系统访问Linux虚拟机配置Linux虚拟机访问网络配置Windows和Linux的连通使用XShell访问Linux,命令和图形窗口。或者直接使用VSCode访问Linux。12案例1:通过SSH终端登录Linux13案例1:通过SSH终端登录Linux14谢谢!Linux系统程序设计教程第2章Linux系统开发环境17第2章Linux下项目开发环境2.1Vim编辑器2.2GCC编译器2.3
Makefile文件的使用2.4
GDB调试器2.5
库2.6
案例2:简易学生成绩计算182.1Vim编辑器Vim的工作模式Vim的基本用法Vim的高级用法192.1Vim编辑器Vim三种模式插入模式:键盘按键被当作文本命令模式:键盘按键被当作命令底行模式:输入“:”“?”“/”后进入,完成某些功能。202.1Vim编辑器Vim的基本用法启动命令提示符后输入“Vim文件名”以下所说的Vim的用法都是在命令模式下,所以在插入模式时要先Esc退出编辑状态。保存不退出:w另存为:w新文件名退出:wq保存并退出:q!不保存退出212.1Vim编辑器Vim的高级用法文本操作复制yyywnyynyw剪切dddwnddndw粘贴
pP222.1Vim编辑器Vim的高级用法行数跳转到某行数字G底行模式,setnu显示行号setnonu取消显示行号撤销u重做
.(句点)搜索
/?232.2
GCC编译器GCC编译器介绍功能强大的编译器,源代码到可执行文件有4个步骤:处理头文件和预编译语句,生成.i文件生成.s汇编代码文件将编译阶段生成的.s文件转换成目标文件.o将目标文件和所用的库函数连接到可执行文件中适当位置,生成可执行文件源代码.ccppcc1asld预处理编译汇编连接242.2
GCC编译器GCC的基本用法1.将源文件生成可执行文件gcc-ooutfileinfile或gccinfile-ooutfile2.将源文件生成目标文件(-c)gcc-cinfile3.生成带有调试信息的可执行文件(-g)gcc-g-ooutfileinfile4.生成汇编文件(-S)gcc-Sinfile5.生成.i文件(-i)gcc-Einfile-oinfile.i252.2
GCC编译器GCC的基本用法6.设置自定义头文件路径(-Idirname)gcc-Idirnameinfile7.设置自定义库文件路径(-Ldirname)gcc-Ldirnameinfile8.编译时加载库文件(-lname)gcc-lnameinfile编译时加上-static选项,强制使用静态库9.增加警告信息gcc-Wallinfile262.3
Makefile文件的使用make对于大型的开发项目来说,可能包括很多源文件,使用make和makefile文件可以清晰地理顺各个源文件之间的关系。。make主要是通过make命令调用makefile文件,通过makefile文件描述源程序之间的相互依赖关系,并自动维护编译工作。调用格式“make目标”,查找makefile文件中指定的目标一般都省略目标直接用make来查找makefile文件中的第一个目标。272.3
Makefile文件的使用makefile文件内容显式规则隐含规则变量定义指示符注释:#后为注释,行注释282.3
Makefile文件的使用1显式规则格式:目标:依赖
[tab]命令注意:[tab]位置按键盘上的tab键举例如果hello不存在则进行编译。如果hello日期没有hello.c日期新则进行编译。hello:hello.c gcc–ohellohello.c292.3
Makefile文件的使用2隐含规则隐含规则是make命令根据一类目标文件(典型的是根据文件名的后缀)而自动推导出来的规则。隐含规则不需要在Makefile命令中明确给出重建特定目标文件所需要的细节描述。【举例】foo:foo.obar.o gcc-ofoofoo.obar.o此时虽然Makefile文件中没有写出foo.o及bar.o文件的生成规则,但是根据隐含规则,make命令将自动寻找foo.c及bar.c并调用cc命令将源文件生成foo.o和bar.o。302.3
Makefile文件的使用3变量定义类似C语言的宏,大小写敏感(推荐大小写搭配名字)变量的引用方式是“$(变量名)”或“${变量名}”。例如,“$(foo)”或“${foo}”就是取变量“foo”的值。$<,$@.$^等都是自动化变量$@目标文件$^所有依赖文件声明时赋初值,使用时变量名前加$,最好用()将名字括起。objects=program.ofoo.outils.oprogram:$(objects) gcc-oprogram$(objects)$(objects):defs.h312.3
Makefile文件的使用4指示符(1)引用另一个Makefile文件include其他Makefile文件名(2)指定Makefile文件中的有效部分Makefile文件中使用条件判断语句指定其中的有效部分,条件判断语句的语法有以下两种。(3)定义一个多行命令①不包含“else”分支。CONDITIONAL-DIRECTIVE
TEXT-IF-TRUEendif②包含“else”分支。CONDITIONAL-DIRECTIVE
TEXT-IF-TRUEelse
TEXT-IF-FALSEendifdefine变量名变量值endef322.3
Makefile文件的使用5注释Makefile文件中将“#”字符后的内容作为注释内容(和Shell脚本一样)处理。当在Makefile文件中需要使用字符“#”时,可以使用反斜线加“#”(\#)来实现(对特殊字符“#”的转义),其表示将“#”作为一字符而不是注释的开始标志。332.3
Makefile文件的使用make执行过程当前目录下按照GNUmakefile、makefile、Makefile的顺序查找makefile文件查找文件中的第一个目标文件如edit。若edit不存在,edit后依赖的文件都存在,并且edit修改时间比依赖文件的时间早,则会执行命令。若edit依赖的.o文件不存在,则在当前文件中查找目标为依赖文件的规则,生成.o文件。通常clean伪目标是用来清除中间文件的,而不是要生成clean文件。一般的makefile文件都加入clean。342.4
输出调试及GDB调试器错误分类编译错误:gcc时出现错误根据错误提示找到错误,从第一个错误开始找。到网上搜索错误提示总结编译错误的解决方法运行错误:gcc正确,运行时出现错误输出调试在程序适当位置加printf提示语句(记得printf中加\n)在调用函数后根据函数返回值结合perror查找错误GDB调试器352.4
输出调试及GDB调试器GDB工具GDB可以为用户做4件事情,帮助用户找出程序中的错误:①运行程序,设置所有的能影响程序运行的因素;②保证程序在指定的条件下停止;③当程序停止时,可以检查发生了什么;④改变程序,这样用户就可以试着修正某个bug引起的问题,然后继续查找另一个bug。GNU的调试器(debugger),字符模式。设置断点b监视变量值p继续执行c删除断点d362.5
库库的概念库函数,由系统提供的,供程序员开发时调用的,完成特定功能的函数。如printf等,一般是.o目标代码。便于编程隐藏细节,降低开发难度和开发周期商业软件,保护知识产权存放函数的文件就像存放函数的仓库,如Glibc库,提供了系统调用和C库的基本函数。Linux下库的形式:静态库、共享库。372.5
库静态库一般以.a结尾,libtest.a编译时:库函数被合并在可执行文件中执行时:提供可执行文件即可可执行文件会变大,适合于小程序调用共享库一般以.so或.so.x结尾,x代表版本,如libtest.so.1编译时:库文件不被合并入可执行文件执行时:提供可执行文件和库文件才能执行可执行文件会比较小,并且几个可执行文件可以共享库,适合于大型项目。382.5
库静态库的创建与使用创建gcc-cfun1.cfun2.c生成目标文件fun1.ofun2.oar-rcslibxxx.afun1.ofun2.o生成静态库libxxx.a使用在test.c中调用库libxxx.agcc-otest_stest.c-L.-lxxx-static生成的可执行文件test_s,可以直接运行。392.5
库共享库的创建与使用创建gcc-fpic-cfun1.cfun2.c生成目标文件fun1.ofun2.ogcc-shared-olibxxx.sofun1.ofun2.o生成共享库libxxx.so使用共享库默认搜索路径是/usr/lib或/lib,拷贝过去
cplibxxx.so/usr/lib使用动态链接库gcc-otest_dtest.c-lxxx或者不拷贝直接使用以下命令编译gcc-otest_dtest.c-L.-lxxx402.6案例2:简易学生成绩计算分析与设计本项目完成一个简易的学生成绩计算功能:从键盘输入N个学生的姓名,年龄,数学成绩,语文成绩四项信息,输入完N个学生信息后,计算各个学生的总成绩和平均成绩,计算完毕后输出每个学生的姓名、年龄、数学成绩、语文成绩、总成绩、平均成绩。要求将输入、计算、输出三个过程分别使用独立函数实现,三个函数分别保存在三个不同的源文件中。412.6案例2:简易学生成绩计算运行效果#lscal.cmakefilestuscorestuscore.hin.cout.cstuscore.cstuscore#./stuscorepleaseinput1
student-name:u1pleaseinput1
student-age:11pleaseinput1
student-ch:60pleaseinput1
student-math:70pleaseinput2
student-name:u2pleaseinput2
student-age:12pleaseinput2
student-ch:89pleaseinput2
student-math:90pleaseinput3
student-name:u3pleaseinput3
student-age:13pleaseinput3
student-ch:78pleaseinput3
student-math:86name
age
ch
math
sum
aveu1
11
60.00
70.00
130.00
65.00u2
12
89.00
90.00
179.00
89.50u3
13
78.00
86.00
164.00
82.00谢谢!Linux系统程序设计教程第3章Linux程序设计初步44第3章Linux程序设计初步3.1程序及进程的存储结构3.2变量的类型修饰符3.3命令行参数及获取3.4环境变量3.5时间管理3.6错误代码3.7标准I/O与文件I/O3.8案例3:设置环境变量3.1程序及进程的存储结构程序(可执行文件)源程序经过编译器处理后生成完成操作的执行者Linux中类型是普通文件,占据磁盘,不占内存ELF格式ExecutableandLinkingFormat可执行和链接格式453.1程序及进程的存储结构程序ELF文件结构(部分):.text字段:保存程序中的代码片段.data字段:保存已经初始化的全局变量和静态变量.bss字段:保存未初始化的全局变量和静态变量.rodata:保存只读的变量.comment:保存编译器版本信息.symtab:符号表,各个目标文件链接的接口463.1程序及进程的存储结构进程程序在数据集合上的一次运行过程,占据内存空间(虚拟内存会使用磁盘空间)可执行文件的内容会被操作系统从磁盘中复制到内存中为了进程的正常运行操作系统还要给进程分配内存空间用以保存其他相关内容。每个进程都有自己独立的处理环境和系统资源473.1程序及进程的存储结构进程48进程在内存中的布局代码区text数据区data未初始化数据区bss堆:用于动态内存分配栈:存放函数的参数值、返回值、局部变量等493.1程序及进程的存储结构Linux进程结构503.2变量的类型修饰符513.2变量的类型修饰符#include<stdio.h>#include<stdlib.h>constinta=1;//只读,数据段staticintb=2;//数据段intc=3;//数据段intd;//bss段intmain(intargc,char*argv[]){char*p;//栈staticinte=5;//数据段staticintf;//bss段charg[]="Helloworld";//栈inth=6;//栈constinti=3;//栈p=(char*)malloc(64);//堆
考虑:(1)变量所占内存字节数(2)变量存储位置printf("&p:%p\n",&p);printf("g:%p\n",&g);printf("h:%p\n\n",&h);printf("i:%p\n",&i);printf("p:%p\n\n",p);printf("d:%p\n",&d);printf("f:%p\n\n",&f);printf("e:%p\n",&e);printf("c:%p\n",&c);printf("b:%p\n\n",&b);printf("a:%p\n\n",&a);return0;}523.3命令行参数及获取命令行参数概念在命令行输入的信息由空格或tab隔开。由于程序都从main函数开始执行,所以命令行输入的信息将被main函数接收,也称为命令行参数。如果程序不需要命令行信息,则main不需要带形参,否则需要加上形参。main原型intmain(intargc,char*argv[]);或intmain(intargc,char*argv[],char*envp[]);533.3命令行参数及获取main函数intmain(intargc,char*argv[]);argc:代表命令行中输入项的个数(包括可执行文件名)argv:数组长度为argc。argv[0]~argv[argc-1]指向命令行各输入项的字符串首地址,argv[argc]存放NULL。字符串数组指针3.3命令行参数练习1:arg.c输出命令行参数541.#include<stdio.h>2.intmain(intargc,char*argv[])3.{4.inti;5.printf("argc=%d\n",argc);6.for(i=0;i<argc;i++)7.printf("argv[%d]=%s\n",i,argv[i]);8.return0;9.}$gcc-oargarg.c$./argaabbargc=3argv[0]=./argargv[1]=aaargv[2]=bb可以测试其他选项553.3命令行参数及获取getopt函数获取命令行参数表3.4与getopt函数有关的变量563.4环境变量代表当前系统环境信息用户可进行查看,增加/修改,删除设置环境变量命令方式在shell中设置,仅在当前shell中有效,重启无效函数方式在程序运行过程中设置,仅在进程过程中有效。永久有效(在文件中修改)所有用户识别:/etc/profile某一用户识别:~/.bashrc重启系统或使用“.文件名”使配置立即生效573.4环境变量命令方式查看变量setecho$varname增加或修改exportvarname=valueexport命令使该变量可以被Shell中启动的其他应用程序访问删除:unsetvarname583.4环境变量函数方式查看变量char*getenv(constchar*var);var代表变量名,成功返回变量值,否则返回NULL。如:char*val=getenv(“PATH”);删除voidunsetenv(cosntchar*var);var代表变量名如unsetenv(“AGE”);593.4环境变量函数方式增加或修改intputenv(constchar*string);参数格式:“变量名=变量值”。如putenv(“AGE=20”);intsetenv(constchar*var,constchar*val,intoverwrite);var变量名,val变量值,overwrite(非0覆盖已存在的变量)如setenv(“AGE”,”20”,1);返回值:成功返回0,否则返回-1。603.5时间管理时间基本概念GMTGreenwichMeanTime格林尼治时间UTCUniversalTimeCoordinated国际协调时间Localtime本地时间613.5时间管理Linux下时间表示方法time_t从1970年1月1日午夜开始计数的秒数值。与系统直接进行交互的类型,UTC结构体structtm将UTC时间根据当前设置的时区进行分解年、月、月日、时、分、秒、周日、年日等。字符串:例如TueJul2309:44:172002structtm{inttm_sec;[0,61],2秒跳秒inttm_min;[0,59]inttm_hour;[0,23]inttm_mday;[1,31]inttm_mon;[0,11]inttm_year;yearsince1900inttm_wday;[0,6]inttm_yday;[0,365]inttm_isdst;夏令时标记};623.5时间管理时间表示转换图633.5时间管理time头文件:#include<time.h>功能:得到系统当前的时间,time_t原型:time_ttime(time_t*t);举例:time_tcurt;curt=time(NULL);或time_tcurt;time(&curt);643.5时间管理localtime头文件:#include<time.h>功能:把time_t转换成本地时间原型:structtm*localtime(consttime_t*t);举例:time_tcurt;time(&curt);structtm*ptm;ptm=localtime(&curt);653.5时间管理ctime头文件:#include<time.h>功能:把time_t转换成本地时间字符串原型:char*ctime(consttime_t*t);举例:time_tcurt;time(&curt);char*pstrt;pstrt=ctime(&curt);663.5时间管理#include<time.h>intmain(){ time_tnowtime; char*nowtime2; structtm*nowtime3; time(&nowtime); printf("%ld\n",nowtime); nowtime2=ctime(&nowtime); printf("%s",nowtime2); nowtime3=localtime(&nowtime); printf("%d-%d-%d:%d:%d:%d\n",nowtime3->tm_year+1900,nowtime3->tm_mon+1,nowtime3->tm_mday,nowtime3->tm_hour,nowtime3->tm_min,nowtime3->tm_sec);}可能的运行结果1765866782TueDec1614:33:0220252025-12-16:14:33:2673.6错误代码errno一个全局的整型变量errno,区分函数执行出错的原因“manerrno”可以查看errno的相关帮助文档0代表没有错误头文件:#include<errno.h>举例:printf("errno1=%d\n",errno);if(fopen("any","r")==NULL){ printf("errno2=%d\n",errno);}683.7标准I/O与文件I/O对于文件的输入/输出一般有两种方式,一个是标准I/O,另一个是文件I/O。操作标准I/O文件I/O打开fopen,freopen,fdopenopen关闭fcloseclose读getc,fgetc,getcharfgets,getsfreadread写putc,fputc,putcharfputs,puts,fwritewrite693.7标准I/O与文件I/O标准I/O的3种类型缓冲。(1)全缓冲。在填满标准I/O缓冲区后才进行实际I/O操作。对于驻留在磁盘上的文件通常由标准I/O库实施全缓冲。一个文件流上执行第一次I/O操作时,相关标准I/O函数通常调用malloc函数获得需使用的缓冲区。(2)行缓冲。当在输入和输出中遇到换行符时,标准I/O库执行I/O操作。一次输出一个字符,但只有在写了一行之后才进行实际I/O操作。当I/O操作涉及一个终端时,通常使用行缓冲。因为标准I/O库用来收集每一行的缓冲区的长度是固定的,所以只要填满了缓冲区,那么即使没有写一个换行符,也进行I/O操作。(3)无缓冲。标准I/O库不对字符进行缓冲存储。例如,如果用I/O函数fputs写15个字符到不带缓冲的文件流中,则该函数很可能用系统调用write将这些字符立即写至相关联的打开文件中。703.7标准I/O与文件I/O一般来说,对于磁盘文件的读写操作是全缓冲的,对于显示器等终端设备是行缓冲的,标准错误输出是无缓冲的。缓冲区类型可以通过setvbuf函数改变。713.8案例3:设置环境变量本项目通过命令行来对进程设置某环境变量的值,如果命令行未给出值则获取当前时间作为该环境变量的值,要求显示该环境变量修改前与修改后的值。723.8案例3:设置环境变量本项目通过命令行来对进程设置某环境变量的值,如果命令行未给出值则获取当前时间作为该环境变量的值,要求显示该环境变量修改前与修改后的值。可能的运行效果#./setenvvarusage:./setenvvarvarname[value]#./setenvvartestbeforetest=(null)aftertest=TueDec1615:13:412025
#./setenvvartesthellobeforetest=(null)aftertest=hello谢谢!Linux系统程序设计教程第4章文件I/O75第4章文件I/O4.1文件系统简介4.2访问文件的内核数据结构4.3文件基本I/O操作4.4文件访问的同步4.5案例4:文件复制命令的实现764.1文件系统简介文件系统操作系统中管理文件的那部分软件及管理文件所需要的各种数据结构。新设备的“格式化”,其实是操作系统按照自己的方式在设备上建立文件系统,就可以存取并管理文件了。对存储设备的空间进行划分,建立初始的数据结构。文件系统的类型Dos、windows采用的FAT、NTFS,Linux采用的ext2(1994)、ext3(2001),ext4(2006,2.6.28内核)——df-TUnix采用的UFS。光盘:DVD-UDF/ISO9660,CD-ISO9660774.1文件系统简介一个简单的Unix文件系统组成引导块:用于引导该分区内操作系统的引导程序超级块:UFS的重要参数,如文件系统的块、索引节点总数,空闲块、空闲索引节点数索引节点表(i节点表):文件系统中索引节点的集合数据块:存储文件数据784.1文件系统简介Linux文件系统—Ext2第一个是引导块,其他空间分成各个块组每个块组中:超级块,块组描述符,数据块位图,索引节点位图,索引节点,数据块794.1文件系统简介VFS虚拟文件系统对象说明superblock对象表示一个具体的可封装的文件系统inode对象表示一个具体的文件dentry对象表示一个目录条目,或路径中的一个分量file对象表示一个与进程相关联的已打开的文件804.1文件系统简介索引节点(inode)Linux系统采用“按名存取”的方式访问文件。除了文件名以外,文件的主要属性信息都存放在inode节点中。目录文件中保存着文件名和索引节点的对应关系。ls-i命令。Linux系统中,每个保存在磁盘的文件包括两部分索引节点inode记录文件属性信息(ls-l)除了文件名。文件的属性包括:文件类型,访问权限,文件主人,组,长度,访问日期等等。数据块存放文件具体内容814.1文件系统简介索引节点(inode)右图为索引节点数据结构图打开文件时系统会将磁盘上文件的i节点信息拷贝到内存VFS的对应该文件的i节点中。注意:硬链接文件的inode与源文件的inode相同。属性数据824.1文件系统简介文件类型普通文件(rugularfile)目录文件(directory)设备文件字符设备文件(characterdevice)块设备文件(blockdevice)FIFO文件(fifo)符号链接文件(symboliclink)socket套接字文件(socket)-rw-r--r--1rootroot582Apr22
2024/etc/profiledrwxr-xr-x3rootroot4096Nov2921:41/home/crw-rw----1rootdialout4,64Dec1612:49/dev/ttyS0brw-rw----1rootdisk8,0Dec1612:49/dev/sdalrwxrwxrwx1rootroot15Dec1612:49/dev/stdin->/proc/self/fd/0prw-------1rootroot0Dec1612:49/run/initctlsrw-rw-rw-1rootroot0Dec1612:49/run/systemd/journal/dev-log834.1文件系统简介文件的访问权限权限是多用户系统中文件管理的重要内容Linux中,用户分为三类:owern,group,other基本访问权限也分为三种:r,w,x特殊权限:setuid,setgid,stickyLinux文件的索引节点inode里面有一个st_mode字段,记录文件类型及权限。该字段共16bit,高四位表示文件类型,低12位表示文件权限。文件所有者文件所属组成员其他用户读read写write执行execute读read写write执行execute读read写write执行execute4.1文件系统简介文件权限的表示方法字母:r读w写x执行-无,如rwxr-xr-x数字:二进制1有0无,如111101101或755符号常量:S_IPwww模式S_I固定,P可为R或W或X,W可为USR或GRP或OTH,用或运算如S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH编程中作为参数只能用数字或宏4.1文件系统简介练习Linux文件类型三种文件权限形式的转换644732635rwx-w-r--S_IRUSR|S_IWGRP|S_IXOTHS_IRUSR|S_IWUSR|S_IXUSR86st_mode结构4.1文件系统简介87884.2访问文件的内核数据结构进程结构体task_struct中有一成员structfiles_struct*files代表当前打开文件,files_struct结构体中包含当前打开文件指针,指向structfile打开文件表某项file结构体中包含打开文件的信息以及位置,并间接指向已经拷贝入内存的文件的i节点。每打开一次文件系统增加一个file表项进程增加一个fd表项(以文件描述符为下标),通过指针指向file表项用户通过文件描述符和系统调用访问该文件。4.2访问文件的内核数据结构89904.3文件基本I/O操作文件描述符用户空间中任何打开的文件都被分配一个唯一的非负整数,标识该打开文件,即文件描述符(filedescriptor)进程默认打开的三个文件描述符标准输入0标准输出1标准错误输出2选用文件描述符中未使用的最小值#define
STDIN_FILENO0
//标准输入文件#define
STDOUT_FILENO
1
//标准输出文件#define
STDERR_FILENO2
//标准错误输出文件914.3文件基本I/O操作常用系统调用open 打开/新建文件creat 新建文件read 读文件write 写文件lseek 定位文件偏移量close 关闭文件92创建/打开文件#include<sys/stat.h>
#include<fcntl.h>intopen(constchar*path,intflags,mode_tperms);说明打开已经存在的文件,perms可省略,即:
intopen(constchar*path,intflags);创建并打开一个不存在的文件,三个参数都要写。93创建/打开文件intopen(constchar*path,intflags,mode_tperms);参数path:文件名,其他目录需要写明路径flags:打开文件的方式,用或运算perms:文件权限,仅创建时需要返回值成功返回最小可用的文件描述符,即访问当前文件所用的文件描述符。失败返回-1(置errno)创建/打开文件——flags参数intopen(constchar*path,intflags,mode_tperms);flags:打开文件的方式以下三个必须选择其一O_RDONLY:只读O_WRONLY:只写O_RDWR:读写其他可选参数(使用|运算)O_CREAT:创建文件时使用,须设置perms。O_TRUNC:若以“写”方式打开文件,长度截为0O_APPEND:每次写操作将在文件末尾追加如:文件不存在则创建,存在则以只写方式打开并截短为0,打开方式表示为?O_WRONLY|O_CREAT|O_TRUNC9494创建/打开文件——perms参数intopen(constchar*path,intflags,mode_tperms);perms:创建文件时设置的文件权限此处可以使用数字(8进制)或符号常量形式表示注意:此处设定的mode的值并不是文件最终的权限,文件最终的权限是按照mode&~umask得到的。默认的umask是00029596创建/打开举例以只读的方式打开/etc/passwd文件intfd=open("/etc/passwd",O_RDONLY);if(fd==-1) perror("open");以读写的方式打开“/home/mydata”,且如果该文件不存在就创建它,权限为“所有者可以读写,所属组成员及其他用户只能读”intfd=open("/home/mydata", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);//第3个参数也可以写成0644if(fd==-1)perror("open");97关闭文件#include<unistd.h>intclose(intfd);功能:关闭文件,释放文件描述符,使之可再利用。参数:fd,文件描述符返回值:成功返回0,否则返回-1(置errno)当一个进程终止时,内核会自动检查并回收该进程所有的文件描述符。
进程打开文件表ptr描述字标签ptr描述字标签…………ptr描述字标签
fd0:
fd2:
fd1:
fd3:打开文件表项……i-nodeptr文件偏移量文件状态标签i-nodeptr文件偏移量文件状态标签当前文件大小inode信息当前文件大小inode信息i-node每次open文件都会返回一个文件描述符,该文件描述符指向一个新的打开文件表项。open与文件描述符9899close与文件描述符通过close可以解除文件描述符指向的打开文件表项。当close一个fd时,fd所指的打开文件表项中引用计数将减1,如果减为0,则不仅释放文件描述符,还释放该打开文件表项。如果某个打开文件表项被释放,则对该文件内存i节点中的引用计数减1,如果减为0,则释放该内存i节点。100读文件#include<unistd.h>ssize_tread(intfd,void*buf,size_tnbytes);功能:从一打开的文件fd中,读取nbytes字节的数据放入buf中。从当前文件偏移量处开始读数据,读完后,当前文件偏移也将改变成功读出的字节个数。参数:fd:文件描述符buf:保存读取数据的缓冲区nbytes:要读取数据的字节数返回值:成功返回已读取字符数,失败返回-1(置errno)101读文件举例intfd;charbuf[100];fd=open(“f1”,O_RDWR);if(fd==-1){perror(“open”);exit(1);}read(fd,buf,sizeof(buf)-1);close(fd);102read说明read返回0表明文件到达结尾。如果希望能读完文件所有的数据,最好通过循环方式调用read,直到读到文件尾为止。有时读到的数据可能比希望读的字节少,但系统不会置错误代码,因为这不是错误(如文件已经到结尾),需要用户自己去推测问题所在。读是从内核缓冲区读,有时,要读的数据可能还在磁盘中,所以有时进程必须等待数据从磁盘拷贝到内核缓冲区。103写文件#include<unistd.h>ssize_t相当于intssize_twrite(intfd,constvoid*buf,size_tnbytes);功能:将buf所指缓冲区中的nbytes个字节写入fd所指示的打开文件中。写操作从当前文件偏移量处开始执行,写完后,当前文件偏移也将改变成功写入的字节数。参数:fd:文件描述符buf:要写入文件的数据区首地址nbytes:要写入文件的数据字节个数返回值:成功返回已写字节数,失败返回-1(置errno)
104写文件举例intfd;fd=open(“f1”,O_RDWR);if(fd==-1){perror(“open”);exit(1);}write(fd,”hello”,strlen(“hello”));close(fd);105write说明open打开文件后,文件读写偏移量自动为0。若open时设置O_APPEND标志,则写之前文件位置会自动定位到文件结尾。如果数据量大的话,可以使用循环的方式分几次把数据写入文件。由于物理介质空间不足等原因将会使得write返回值小于计划要写入文件的字节个数。实际上,write并不真正把数据写入磁盘,仅仅是传递给内核缓冲区,系统会定时将内核缓冲区的数据写入磁盘。如果出现磁盘等错误的话,数据就会丢失。write等待数据写入内核缓冲区后才返回。106文件偏移量--引入将f1文件以读写方式打开,先向文件写入“helloworld”,然后从文件中读出刚刚写入的内容,然后使用write函数将刚刚读出的内容打印到屏幕上。有什么问题吗?无法读出刚写入的内容原因:对一次open返回的fd对应的文件进行写操作后,当前偏移量已经移到写后的位置了,再继续读自然什么也读不出来。107文件偏移量非负整数,标识下一次读或写文件的位置。通常读写操作都从当前文件偏移量处开始。文件偏移量保存在对应的打开文件表中每open一次文件,就能得到一个新的打开文件表项,因此每次open都可以得到一个独立的文件偏移量。一个进程多次open同一个文件,由于得到不同的fd和打开文件表项,因此每次fd都拥有各自独立的文件偏移量。108文件偏移量举例fd1=open(“ex1”,O_WRONLY);fd2=open(“ex1”,O_RDONLY);fd3=open(“ex2”,O_RDWR);问题1:open后当前文件位置为0,如果向fd1中写入100个字节,接着从fd2中读出100字节,那么读出的数据会是刚刚写入的100个字节吗?问题2:如果向fd3中写入100个字节,接着再从fd3中读出100字节,能读出刚刚写入的100个字节吗?若要设置读写偏移量,需要使用lseek系统调用函数109文件定位函数#include<unistd.h>off_tlseek(intfd,off_tpos,intwhence);参数fd:文件描述符whence:取下面其中一个值SEEK_SET:代表文件开始,即设为posSEEK_CUR:代表当前位置,即设为当前值+posSEEK_END:代表文件结尾,即设为文件长度+pospos:可正、负、0,代表相对whence的偏移值。返回值成功返回设置后的当前文件偏移量,off_t相当于long。失败返回-1(置errno)110文件定位函数举例lseek常用的几种方式设置文件的某个绝对位置
lseek(fd,值,SEEK_SET);查找文件偏移量的当前位置
off_twherewhere=lseek(fd,0,SEEK_CUR);查找文件结尾
off_twherewhere=lseek(fd,0,SEEK_END);111lseek说明内核大部分定位偏移量时是隐含的,不显式调用lseekopen:定位到第1个字节read、write:将文件偏移量增加读或写的字节数用O_APPEND标志打开文件时,每次写之前将偏移量定位到结尾。通常文件偏移量返回非负整数,甚至可能比文件大若文件偏移量位于或超过结尾时,read会返回0(代表文件结尾)如果文件偏移量比文件长度大,则下一次write操作时自动将文件长度延长到需要的大小,并将中间的字节填充为0(NULL)。112lseek练习编程:rw.c向文件写入“helloworld”,然后再读出并显示到屏幕上。下列操作都是正确的:lseek(fd,20,SEEK_SET);//从文件开始位置移动20字节,移动后为20lseek(fd,120,SEEK_SET);//从文件开始位置移动120字节,移动后为120lseek(fd,20,SEEK_CUR);//从文件当前位置移动20字节,移动后为70lseek(fd,-20,SEEK_CUR);//从文件当前位置移动-20字节,移动后为30lseek(fd,60,SEEK_CUR);//从文件当前位置移动60字节,移动后为110lseek(fd,20,SEEK_END);//从文件末尾位置移动20字节,移动后为120lseek(fd,-20,SEEK_END);//从文件末尾位置移动-20字节,移动后为80而下列操作都是错误的:lseek(fd,-20,SEEK_SET);
//从文件开始位置移动-20字节lseek(fd,-60,SEEK_CUR);
//从文件当前位置移动-60字节lseek(fd,-120,SEEK_END);
//从文件末尾位置移动-120字节113文件练习【例4-6】文件基本I/O操作。编写一个程序,两次打开同一个文件进行读写操作,并观察结果。【例4-7】编写一个父子进程访问同一个文件的程序。114ANSIPOSIX写文件时,进程将数据复制到内核缓存,缓存未满则不将缓存排入输出队列,而是等满或者需要时才排入输出队列,然后等到达队首时才执行写操作,即延迟写。磁盘文件内核缓冲区用户缓冲区进程磁盘文件内核缓冲区进程4.4文件访问的同步115同步内核缓冲区为保证磁盘上的文件与内核缓冲区中内容一致,可以使用sync、fsync、fdatasync更新内核缓冲区,即将缓冲区内的数据写入磁盘。116sync/fsync/fdatasync#include<unistd.h>voidsync(void);将缓存所有数据排入输出队列,不等写入磁盘结束立即返回。intfsync(intfd);对内核缓存中fd指定文件进行刷新,等待写入结束才返回。成功返回0,否则返回-1intfdatasync(intfd);对内核缓存中fd文件的数据部分进行刷新,不包括文件属性,等待写入结束才返回。成功返回0,否则返回-11174.5案例4:文件复制命令的实现在UNIX中,基本文件的访问过程分为如下步骤:(1)打开文件/创建新文件。(2)访问文件(包括定位读写指针、读文件、写文件等操作)。(3)最后关闭文件。打开/创建文件使用系统调用open()/creat();访问文件的操作包括读文件read()、写文件write()、定位文件读写指针lseek()等;关闭文件使用系统调用close()。“文件复制命令的实现”项目将通过打开源文件、创建目标文件、从源文件中读出数据写入目标文件、关闭源目标文件这样的过程实现文件的复制,这将用到上述的系统调用。1184.5案例4:文件复制命令的实现可能的运行效果#./mycpUsage:./mycp
fromfilename
tofilename#./mycpf1f2谢谢!Linux系统程序设计教程第5章文件属性121第5章文件属性5.1获取文件属性5.2用户/组ID与名字的转换5.3硬链接与符号链接5.4dup/dup25.5文件属性的修改5.6案例5:显示文件长格式信息5.1文件属性磁盘上的文件包括inode和数据块两部分。ls–l查看属性,cat、less等查看内容inode中保存文件的属性信息,不包括文件名。文件名和inode号对应关系保存在文件所在目录文件中。调用open时创建内存中的i节点(structinode),从磁盘i节点拷贝信息。常见的文件属性数据类型为structstat,可使用stat系列函数获取。122structstatstructstat{ dev_t st_dev; //文件所在的设备ID
ino_t st_ino; //i节点号
mode_t st_mode; //类型权限
nlink_t st_nlink; //硬链接个数
uid_t st_uid; //uid gid_t st_gid; //gid dev_t st_rdev; //若是特殊文件,设备ID
off_t st_size; //文件大小(字节数)
time_t st_atime; //上次访问时间
time_t st_mtime; //上次修改内容时间
time_t st_ctime; //上次文件信息修改时间
blksize_t st_blksize; //块大小(字节)
blkcnt_t st_blocks; //文件块个数
};123stat、fstat、lstat函数获得文件属性。#include<sys/stat.h>intlstat(cosntchar*path,structstat*buf);重点
intstat(constchar*path,structstat*buf);intfstat(intfd,structstat*buf);功能:获取文件属性stat:通过文件路径获取fstat:通过文件描述符获取lstat:通过文件路径获取,若查询符号链接文件,仅查其本身属性而不是所链接文件属性。参数:path:文件路径fd:文件描述符buf:返回的文件属性(结构体)返回值:成功返回0,否则返回-1(置errno)124lstat举例获取/etc/passwd属性structstatbuf;intrt;rt=lstat(“/etc/passwd”,&buf);if(rt==-1) perror(“lstat”);125Linux文件类型及权限126Linux文件类型七种文件类型的二进制表达S_IFMT 0170000 文件类型的二进制掩码S_IFREG 0100000 常规文件-S_IFDIR 0040000 目录文件dS_IFBLK 0060000 块设备文件bS_IFCHR 0020000 字符设备文件cS_IFIFO 0010000 管道文件pS_IFSOCK 0140000 套接字文件sS_IFLNK 0120000 符号链接文件l127文件类型检测判断某个文件的类型方法一:使用lstat获取文件属性structstat,对成员st_mode调用一系列宏进行判断。方法二:使用lstat获取文件属性structstat,对成员st_mode通过位操作以及文件类型宏进行判断。128判断文件类型——方法一structstatbuf;lstat(“filename”,&buf);判断buf.st_mode&S_IFMT的值是否与各个文件类型宏相等,相等即为某类型。switch(buf.st_mode&S_IFMT){ caseS_IFDIR:printf("d");break; caseS_IFLNK:printf("l");break; caseS_IFREG:printf("-");break; default:printf("?");}129判断文件类型——方法二structstatbuf;lstat(“filename”,&buf);宏操作返回真代表是该类型文件。S_ISREG(buf.st_mode)常规文件S_ISDIR(buf.st_mode)目录文件S_ISCHR(buf.st_mode)字符设备文件S_ISBLK(buf.st_mode)块设备文件S_ISFIFO(buf.st_mode)管道文件S_ISLNK(buf.st_mode)符号链接文件S_ISSOCK(buf.st_mode)套接字文件130文件访问权限三组用户九种访问权限S_IRUSRS_IWUSRS_IXUSRS_IRGRPS_IWGRPS_IXGRPS_IROTHS_IWOTHS_IXOTH文件访问权限判断根据st_mode低9位进行判断,如st_mode&S_IRUSR:非0用户可读,0用户不可读格式:st_mode&S_Ipwww:非0www可p,0www不可p131练习(myls.c)输出文件类型(-dbcpls)测试以下给出的文件,看程序是否执行正确。-rw-r--r--1rootroot58112月52019/etc/profiledrwxr-xr-x5rootroot40966月2815:22/home/crw-rw----1rootdialout4,648月1216:21/dev/ttyS0brw-rw----1rootdisk8,58月1216:21/dev/sda5lrwxrwxrwx1rootroot38月1216:21/dev/cdrom->sr0prw-------1rootroot0Aug1216:14/run/initctlsrw-rw-rw-1rootroot0Aug1216:14/run/systemd/journal/dev-log132在如下函数中输出文件类型字符,文件名从参数给定voidmyls(charconst*name){}文件权限修饰位11:setuid,设置用户id位显示在拥有者执行权限位10:setgid,设置组id位显示在所属组执行权限位9:sticky,粘附位显示在其他用户执行权限位文件权限修饰位宏S_ISUID0004000S_ISGID0002000S_ISVTX0001000带x无x133文件权限修饰位如何判断权限修饰位?(以设置用户ID位举例)if((buf.st_mode&S_ISUID)==0)
(buf.st_mode&S_IXUSR)?putchar(‘x’):putchar(‘-’);else
(buf.st_mode&S_IXUSR)?putchar(‘s’):putchar(‘S’);文件权限修饰位宏S_ISUID0004000S_ISGID0002000S_ISVTX0001000134练习加入权限修饰位的判断测试:创建文件a,使用以下命令设置a的权限并做输出测试chmod7777arwsrwsrwtchmod0777arwxrwxrwxchmod7666arwSrwSrwTchmod0666arw-rw-rw-1351365.2用户/组ID与名字的转换获取用户ID和用户组ID后得到的是数字,有时需要获取对应的用户名或组名等信息。用户信息保存在/etc/passwd中,组信息保存在/etc/group中1375.2用户/组ID与名字的转换通过用户ID得到用户信息#include<pwd.h>struct
passwd*getpwuid(uid_t
uid);通过用户组ID得到用户组信息#include<grp.h>structgroup*getgrgid(gid_t
gid);1385.2用户/组ID与名字的转换通过用户ID得到用户信息#include<pwd.h>structpasswd*getpwuid(uid_tuid);返回值:成功返passwd结构体指针,否则返NULL(置errno)structpasswd{char*pw_name;//用户名
char*pw_passwd;//用户密码
uid_tpw_uid;//用户IDgid_tpw_gid;//用户所在组IDchar*pw_gecos;//真实名字
char*pw_dir;//用户主目录
char*pw_shell//用户所用Shell};1395.2用户/组ID与名字的转换通过用户组ID得到用户组信息#include<grp.h>structgroup*getgrgid(gid_tgid);返回值:成功返回结构体指针,否则返回NULL(置errno)structgroup{char*gr_name;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026福建泉州市南安市码头镇政府招聘专职调解员1人笔试备考试题及答案详解
- 2026广西桂林市叠彩区招聘劳务派遣人员3人笔试模拟试题及答案详解
- 2025年鹤岗市兴山区社区工作者招聘考试试题及答案详解
- 2026云南昆明市中医医院下半年面向社会招聘编外人员81人笔试备考试题及答案详解
- 政工师考试试题及参考答案
- 2026年哈尔滨市第五十九中学校临时招聘2人考试备考试题及答案详解
- 2026聊城东阿某国企招聘笔试备考题库及答案详解
- 2026湖北荆州技师学院招聘4人考试备考题库及答案详解
- 2025年济宁市任城区网格员招聘考试试题及答案详解
- 2026年黑龙江省绥化市社区工作者招聘笔试备考题库及答案详解
- 通信汛期安全生产课件
- 《肺叶手术的麻醉》课件
- 一元一次方程和分式方程复习教案 人教版
- 脚手架拆除方案报审
- 2024外贸佣金合同中英文版
- 钻孔灌注桩桩头质量缺陷处理方案样本
- 法院送达地址确认书(诉讼类范本)
- TDTG5024斗式提升机机座及总体部分设计
- 3%水泥土试验段施工方案
- GB/T 36174-2018金属和合金的腐蚀固溶热处理铝合金的耐晶间腐蚀性的测定
- 第二章常用低压电器基本原理课件
评论
0/150
提交评论