目录
一:理解设备和文件的关系
可读可写可执行 rwx
通过 命令ll 查看文件权限
9个权限位,3个一组,分别是文件拥有者,同组成员用户,其他用户
表示当前文件或者文件夹的文件拥有者,同组和其他用户的权限
第一位是d:代码目录
第一位是 -:代表文件
二:Linux中的设备管理
Linux采用文件系统管理硬件设备
对于计算机/操作系统来说,屏幕网卡键盘鼠标都是硬件设备,也就是说Linux下有一个文件就可以代表一个硬件
Linux采用文件系统管理硬件设备,所有的设备都看成是特殊的文件,从而将硬件设备的特性及管理细节对用户隐藏起来,实现设备无关性
Linux文件系统的文件分类,如下图所示
如/dev可以管理硬件设备,/mnt可以U盘挂载...
Linux系统要想管理硬件,就是通过文件来管理的,因此,文件怎么操作,非常重要!
因为Linux下的文件的操作,就相当于是对设备的操作了
可以通过【系统调用】open( ) 来打开设备文件
fopen叫做API函数,API函数 导入的头文件中包含了函数原型才可以调用函数,API在使用一个函数时必须要先引入正确的头文件
三:系统调用和函数库调用的区别
系统调用比函数库调用效率更高 ,因为少了函数库这一过程
缺点:系统调用(无法跨平台、Linux开发就只能Linux下使用,不能window下使用)
区别主要在于:效率问题、和是否跨平台的优势的问题
p表示的是用户的应用程序 (软件运行起来的效果)
当有一个软件运行起来-比如打开一个文件-若是fopen就来自于上图中的函数库,函数库就需要先找头文件是否链接成功,如果引入正确就可以进行接下来操作系统中的某个磁盘上的文件操作,中间接入了一个函数库
应用程序如果想要打开文件,还有一种直接去到操作系统的核心,这种方式也就是系统调用
由上述知,函数库调用明显多出一个过程,而且这个过程还需要进行判断(头文件是否引入成功,头文件下是否包含有要使用的函数还需要进行查找-一定有一个判断和查找的过程-编译)(编译判断语法正确与否,链接在引入头文件,然后再匹配头文件下的所有的函数,最后是运行)
函数库的调用(用户编程接口API函数)存在弊端-代码执行的效率更低,而系统调用则是直接调用操作系统核心,直接操作磁盘,效率更高
window操作系统和Linux操作系统都有各自的命令和函数,这两个操作系统完全不同
因此Linux下的open( )函数在window下不能运行
由此可知,系统调用必须有系统的要求(系统环境的要求),使用什么操作系统就需要使用什么操作系统下的函数才有效,跨操作系统无效
对于函数库,没用跨操作系统的问题,因为函数库相当一个工具包(软件),不管什么操作系统,有这个软件即可使用(VC++6.0包含所有c语言函数在window在ubuntu都可以用)
对于函数库,不存在跨平台操作的任何问题,程序员编写代码无论放在哪个电脑用都可以(只要软件环境没有问题即可)
系统调用是需要学习的,因为Linux系统调用速度快效率高(但是不能跨平台),写的程序如果对于用户不是Linux那么用户将无法使用此开发的软件,后面的网络编程开发(需要自己动手编写服务器的代码),从服务器来看,如果是Linux操作系统,那么系统调用明显合适
很多公司的服务器默认都是Linux(Linux操作系统开源,开源(开放源代码)就有一个非常大的好处,可以拿到源代码根据企业自己需求进行修改,比如麒麟,华为鸿蒙就是Linux开源搬过来华为自己修改成自己的东西,对于开源的代码,所有业内高手都可以看到,在企业开发的时候,就会不断地将有出现过的漏洞进行补全,不断地完善操作系统的漏洞,系统也会变得越来越安全),但是window操作系统就不开源,经常更新,不开源的那些代码只有微软公司的几个开发人员知道,有什么样的漏洞,也只有那么些人不断测试才能发现那些漏洞,毕竟一个团队的技术是有上限的。对于漏洞,业内高手不能发现,只能通过用户不断发现问题进行反馈,然后微软团队再不断打补丁,所有微软经常更新,安装下载补丁。这就是开源和不开源的差别,ubuntu中就不会出现这样的情况。作为企业开发商来说,很多服务器就使用Linux操作系统,因此Linux内核编程就非常值得我们学习了,Linux内核编程的命令,操作,就需要学习。在后面可以做服务器开发。
函数库调用和系统调用
四:设备管理的特点
每个设备都对应文件系统中的一个索引节点,都有一个文件名
应用程序通常可以通过系统调用open()打开设备文件,建立起与目标设备的连接
对设备的使用类似于对文件的存取
设备驱动程序都是系统内核的一部分,它们必须为系统内核或者它们的子系统提供一个标准的接口
设备驱动程序使用一些标准的内核服务,如内存分配等
五:设备分类
按设备属主关系
系统设备
用户设备
按设备信息交换单位来分
字符设备
块设备
按设备共享属性来分
独享设备
共享设备(打印机,U盘)
六:设备工作原理
七:设备或文件操作两种方式
用户编程接口 API系统调用
八:系统调用
系统调用是操作系统提供给用户的一组“特殊”接口
系统调用并非直接和程序员或系统管理员直接打交道,而是通过软中断的方式向内核提交请求,从而获取内核函数的服务入口(系统调用表)
系统调用让系统从用户空间进入内核空间内运行,运行后将结果返回给应用程序(内核态->用户空间)
九:系统调用和系统API等区别
系统API
主要是通过C库libc来实现,程序员多采用这种方式与内核交互,这些API通过系统调用来实现
系统命令
系统管理员采用系统命令与内核交互,是一个可执行文件,通过系统API及系统调用来实现
外壳程序
一系列系统命令和SHELL脚本共同组合成的程序
十:C库的文件操作和文件系统调用
C库的文件操作
文件系统调用
open系统调用
read系统调用
write系统调用
create系统调用
close系统调用
mkdir系统调用
十一: 文件描述符fd 和 特殊文件描述符号
文件描述符fd
每个进程PCB结构中有文件描述符指针,指向files_struct的文件描述符表,记录每个进程打开的文件列表
系统内核不允许应用程序访问进程的文件描述符表,只返回这些结构的索引即文件描述符ID(File Description)给应用程序
Linux系统中,应用程序通过这些文件描述符来实现让内核对文件的访问
每个进程能够访问的文件描述符是有限制的,通过#ulimit –n可以查看
特殊文件描述符号
标准输入STDIN_FILENO
标准输出STDOUT_FILENO
标准错误STDERR_FILENO
每个进程被加载后,默认打开0,1,2这三个文件描述符
十二:open,write,read系统调用
open系统调用有两种,如下
有几种方法可以获得允许访问文件的文件描述符
最常用的是使用open()(打开)系统调用
函数原型
int open(const char *path, int flags);
参数
path :文件的名称,可以包含(绝对和相对)路径
flags:文件打开模式
返回值
打开成功,返回文件描述符;
打开失败,返回-1
函数原型
int open(const char *path, int flags,mode_t mode);
参数
path :文件的名称,可以包含(绝对和相对)路径
flags:文件打开模式
mode: 用来规定对该文件的所有者,文件的用户组及系统中其他用户的访问权限,则文件权限为:mode&(~umask)
返回值
打开成功,返回文件描述符;
打开失败,返回-1
打开文件的方式
访问权限
write系统调用
用write()系统调用将数据写到一个文件中
函数原型:int write(int fd,void *buf,size_t nbytes);
函数参数:
fd :要写入的文件的文件描述符
buf: 指向内存块的指针,从这个内存块中读取数据写入 到文件中
nbytes: 要写入文件的字节个数
返回值
如果出现错误,返回-1
如果写入成功,则返回写入到文件中的字节个数
read系统调用
一旦有了与一个打开文件描述相连的文件描述符,只要该文件是用O_RDONLY或O_RDWR标志打开的,就可以用read()系统调用从该文件中读取字节
函数原型:
int read(int fd, void *buf, size_t nbytes);
参数
fd :想要读的文件的文件描述符
buf: 指向内存块的指针,从文件中读取来的字节放到这个内存块中
nbytes: 从该文件复制到buf中的字节个数
返回值
如果出现错误,返回-1
返回从该文件复制到规定的缓冲区中的字节数,文件结束,返回0否则
注意点:文件的随机读写
到目前为止的所有文件访问都是顺序访问
这是因为所有的读和写都从当前文件的偏移位置开始,然后文件偏移值自动地增加到刚好超出读或写结束时的位置,使它为下一次访问作好准备
有个文件偏移这样的机制,在Linux系统中,随机访问就变得很简单,你所需做的只是将当前文件移值改变到有关的位置,它将迫使一次read()或write()发生在这一位置(除非文件被O_APPEND打开,在这种情况下,任何write调用仍将发生在文件结束处)
lseek系统调用