Linux系统编程:文件系统总结

目录和文件

获取文件属性

获取文件属性有如下的系统调用,下面逐个来分析。
在这里插入图片描述

stat:通过文件路径获取属性,面对符号链接文件时获取的是所指向的目标文件的属性

从上图中可以看到stat函数接收一个文件的路径字符串(你要获取哪个文件的属性),还有一个stat类型的结构体指针的缓冲区,然后我们所需要的该文件的属性全都会保存在这个stat类型结构体的缓冲区buf中,我们要查看的话通过使用这个缓冲区即可查到。

下面来具体看一下stat结构体的定义:
在这里插入图片描述
我们接下来来简单的使用一下这个系统调用,这个程序用来查看某个文件的大小:
在这里插入图片描述

在这里插入图片描述
可以看见正常输出,同理stat结构体内定义了的属性都是可以直接使用的。

fstat: 通过文件描述符获取属性

lstat: 面对符号链接文件时获取的是符号链接文件的属性

文件访问权限

文件访问权限的内容全部都在stat结构体中的 st_mode这个属性中,st_mode是一个十六位的位图,用于表示文件类型、文件访问权限及特殊权限位。

在man手册中我们可以看到对于文件权限这一块,Linux给我们提供了对应的宏来实现对文件的判断:
在这里插入图片描述

举一个例子:
在这里插入图片描述
在这里插入图片描述
除了上述这种宏的形式外,文件权限还有一个对应的位图,但这里不展开论述(我的Ubuntu系统中手册没有对应的说明,也有可能是我没找到,但是宏定义的形式已经够用啦)。

umask

我们之前说过,如果在终端上创建文件,假如没特意设定其权限值的话,那么将会产生一个默认的权限,这就是因为有umask的存在才导致的,其求权限公式是:在这里插入图片描述

其中0666是系统默认先赋予的(前提是我们没指定),然后将umask的值按位取反后,二者相与最后得到这个新文件的最终权限。

使用umask可以得到当前系统的umask值:
在这里插入图片描述
使用umask 后跟四个位的数字可以更改这个值,但重启终端之后又会恢复原样。

umask这种机制的存在,就是为了防止产生权限过于松散的文件。

这个命令实际上也是一个系统调用:
在这里插入图片描述
这就不再演示,看文档就能明白。

文件权限的更改/管理:chmod,fchmod

这两个也是系统调用,并非是我们终端上所使用的命令嗷:
在这里插入图片描述
也比较简单,不再赘述。

粘住位

粘住位也叫 t 位,其一开始的作用是给一个可执行的二进制的命令设置一个当前 t 位,就是把某一个命令的使用痕迹给保留下来,为了在下一次装载这个模块的时候调用比较快。

比如有的命令常用,那么就在内存当中保存它的使用痕迹,下次调用就比较快。

但是随着技术革新现在这一点不需要了,现在常用这个 t 位来对某一个目录进行设置:
在这里插入图片描述
可以看见tmp目录的权限的最后一位就是 t 位。

这就意味着各个用户对该目录以及该目录下的文件进行操作时就会有点特殊化了。

这里了解一下即可。

文件系统:FAT、UFS(二者都是Unix系统早期的文件系统,后者开源前者不开源)

文件系统:就是用来解决文件或者数据的存储格式和管理等问题。
关于这个老师也只是讲了概述性质的内容,感兴趣可以自己去找点资料看,这里不再赘述。

硬链接与符号链接

硬链接与符号链接的关系以及二者是什么就不赘述了,主要提一下和这两个东西相关的系统调用:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
另外注意:硬链接与目录项是同义词,且建立硬链接有限制:不能给分区建立,不能给目录建立。

符号链接优点:可跨分区,可以给目录建立。

时间相关更改命令:utime

在这里插入图片描述
可以看出utime系统调用修改的是文件最后一一次读写的时间。

上面的第二个参数就是一个结构体参数utimbuf,其定义在上图的下方,可以看到我们通过该结构体可以对access time(最后读的时间)和modification time(最后写的时间)进行修改(比较少用啦)。

后面我们还有个专题专门来讲解时间这部分。

目录的创建和销毁

在这里插入图片描述
在这里插入图片描述

更改当前工作路径

在这里插入图片描述

分析目录/读取目录内容

这一节的内容我们需要使用到递归,可以用两种方式实现,一种是直接使用glob函数:
在这里插入图片描述
我们来写个小例子详细解释一下这个函数的使用,这个例子程序的作用是查看某个目录下面以a开头的.conf文件有多少:
在这里插入图片描述
在这里插入图片描述
还有一种是使用一大堆函数来堆叠使用达到相同的效果,opendir、closedir、readdir、rewinddir、seekdir、telldir:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
那么我们依然可以写一个小例子程序来进行一个练习,这个程序用来描述/etc文件目录下共有多少文件:
在这里插入图片描述

目录解析实例(一)

实现du功能:
在这里插入图片描述
du指令的功能就是以字节为单位来显示当前路径下所有文件所占的K数,比如上面第一个例子就表示fileSystem目录就占36KB大小的数据。

为什么要用到递归呢?
在这里插入图片描述
如上图所示,若要展示的文件目录下还有子目录也一并会打印出来,那么肯定是要使用递归来查询所有的内容。

那么接下来我们来实现这个功能:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

系统数据文件和信息

/etc/passwd

在这里插入图片描述

打开该文件:
在这里插入图片描述
这个文件详细记录了系统的用户信息、组信息以及一些其它的系统数据等等,具体可以参考APUE这本书,这里不再赘述,只介绍跟这个有关的几个函数:

getpwuid() 和 getpwnam()

在这里插入图片描述
这两个函数都是通过给定的参数比如用户名或者用户id返回其对应的用户信息,用户信息会放在一个passwd的结构体中:
在这里插入图片描述
也就是可以获取上述的信息。
例子程序:
在这里插入图片描述

在这里插入图片描述

/etc/group

一样,先打开看一下这个文件:
在这里插入图片描述
这个顾名思义就是和用户组相关的信息都在这个文件里面,和上面说的类似,也有两个函数:

getgrgid() 和 getgrgrnam()

在这里插入图片描述
和之前类似,结构体group的定义如下:
在这里插入图片描述
例子程序就不再赘述。

/etc/shadow

这个文件叫阴影文件,里面存放了一些口令信息,是非常重要且隐私的文件。
在这里插入图片描述
在这里插入图片描述
因为这个内容比较隐私,所以就不放图了。
但和之前的内容一样,会提到几个函数:

getspnam() 和 getspent() 以及crypt()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结构体spwd的定义如下:
在这里插入图片描述
crypt是加密函数,其man手册描述如下:
在这里插入图片描述
其中phrase是原串也就是原文,setting就是加密的方式,然后这个函数返回一个被加密了的字符串。

一个简单的加密程序:

在这里插入图片描述
在这里插入图片描述
shadow文件注意一定要使用root用户来进行操作嗷,这里我没用root权限所以执行不了,不再赘述。

时间戳

之前提到过,stat系统调用下有个关于time_t的时间类型(这好像是红帽系列的Linux是time_t类型,我用的Ubuntu,所以有点不不太一样好像):
在这里插入图片描述
在这里插入图片描述
关于这一块,我们需要掌握下面几个函数:
time()、gmtime()、localtime()、mktime()、strftime()。

time()

在这里插入图片描述
其作用是以秒为单位获取时间,其用法如下:
在这里插入图片描述
这个stamp可以作参数也可以直接作返回值,因为效果是一样的,从man手册中可以看出来。

gmtime() 和 localtime()

在这里插入图片描述
结构体tm的定义如下:
在这里插入图片描述

gmtime很明显就是将一个time_t类型的时间戳转换成tm类型的结构体,同理localtime也是一样不再赘述。

mktime()

这个函数实际上是上面两个函数的逆向过程:
在这里插入图片描述
将结构体tm又逆向回一个time_t类型。

strftime()

在这里插入图片描述
这个函数的作用是格式化时间和日期,其作用是将一个tm结构体(第四个参数)当中提出来我所需要的结构体字段(第三个参数),然后把这个字段放到由第一个参数和第二个参数所构成的缓冲区中(s是字符串,max就是最大字节数)。

第三个参数格式在man手册中有对应的操作,下图中的%a等就是第三个参数所需要的格式字符串:
在这里插入图片描述
简单的使用:
在这里插入图片描述

时间专题实例

程序一,实现类似下面内容的输出,每一秒输出一次带行号:
在这里插入图片描述

程序如下:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
再来一个示例程序,该程序用来求从现在开始一百天后是哪一天:
在这里插入图片描述
在这里插入图片描述

进程环境

注意目前还是讲的单进程内容。

main函数

main函数本身就是一个进程或者说线程,在后面会再提及。

进程的终止(正常终止和异常终止)

正常终止:

从main函数返回,如return 0;
调用exit;
调用_exit或者_Exit;
最后一个线程从其启动例程返回;
最后一个线程调用pthread_exit;

return 0和 exit(0)有什么区别?
返回 return 0 表示是给当前这个进程的父进程看的,这是一个约定俗成的写法,没有什么特别的说法,而exit则是一个函数(钩子函数):
在这里插入图片描述
可以看见exit函数可以引发进程的正常终止,与之相关的还有一个函数是atexit()钩子函数(onexit函数与其类似,但atexit用的比较多):
在这里插入图片描述
当进程正常终止时这个atexit()函数会被调用。

我们写一个小例子来感受一下:
在这里插入图片描述

在这里插入图片描述

而_exit和_Exit则是系统调用,也就是说上面的exit函数是依赖于这二者的:
在这里插入图片描述
那么与exit有什么区别呢?

exit函数被调用时会直接将整个程序的执行步骤全部执行,比如钩子函数该调的调用,缓冲区该刷新的刷新,那么此时如果是程序出了问题的情况我们还是调用exit函数退出的话,就很可能会将本来的小错误给扩大化(因为影响了后面钩子函数啊、缓冲区中的内容,造成了一步错步步错的效果),所以此时肯定不能使用exit,为了阻止错误进一步扩散,我们可以使用_exit或者_Exit,这两个函数就不会去执行后面的步骤而是直接退出,或者使用abort信号也行。

剩下部分的解析都涉及信号的内容,这些会在后面说到,这里不再赘述。

异常终止:

调用abort;
接到一个信号并终止;
最后一个线程对其取消请求做出响应;

异常终止和正常终止的情况非常重要,必须要熟记。

命令行参数的分析

这一块内容涉及两个函数:getopt() 和 getopt_long(),一个接收命令行短格式一个接收长格式。
在这里插入图片描述
接下里我们使用 getopt() 函数来实现一个小程序,可以根据命令行输入 -m 表示获得现在是几月, -h 表示现在是几点, -y表示现在是几年等等:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
运行结果:
在这里插入图片描述

环境变量

main函数在最开始的时候其实有三个参数,其中第三个参数就是环境变量。
环境变量的本质其实就是:KEY = VALUE;
查看环境变量,使用export命令:
在这里插入图片描述
可以看到我们使用的很多命令在环境变量里面都是有的,这是我们能够在shell窗口下很便捷的使用各种命令的原因(因为如果不是这样的话我们就得写很长的命令串)。
比如 ls 命令就在PATH环境变量里,使用ls命令时shell就会去PATH里面寻找 ls 命令的二进制可执行文件并执行。

PATH环境变量所保存的二进制可执行文件就叫Shell 的外部命令处理,也就是说这类文件是存储在磁盘上的,我们能找到它并对它进行调用。内部命令处理就是OS自带的,比如进程调度啊、管道啊之类的。

在这块会用到一个值叫 environ ,它相当于一个全局变量,被用来保存所有环境变量的内容。
它存放的形式非常像main函数中的 argv[] 参数数组,是一个二维数组,其中每一行是一个字符串,我们写个小例子来看一下:
在这里插入图片描述

在这里插入图片描述

关于环境变量我们需要知道的几个函数:getenv()、setenv()、putenv();
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

C程序的存储空间布局

在这里插入图片描述
可以使用 pmap 命令来查看一个进程在当前系统下的内存分布情况:
在这里插入图片描述
当我们将位于各区内的代码都写在一个c文件中并运行时,通过 pmap 指令就能知道其各个变量会被存放在哪个区了,这是一个很好的学习方法。

使用 ps axf 可以以一个树状结构来查看当前系统中的所有进程以及进程父子关系:
在这里插入图片描述

函数跳转

这里不是说通常意义上的调用函数之后就跳转到另一个函数了,这里强调的是在不改变现有数据结构的情况下实现函数的跳转。
比如递归这种操作,递归的本质就是压栈,那么若此时一个函数位于栈顶想调用栈底的函数怎么办呢?goto语句也只能实现在函数内部的跳转,我们需要类似于goto这样的机制来实现在各个函数间进行跳转,所以又有几个函数需要学习:
setjmp() 和 longjmp();

setjmp函数是用来设置跳转点的,longjmp函数是用来进行从某个位置跳回到某个跳转点的。

这两个函数可以进行安全的跨函数跳转。

来试一下:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
可以看见现在是正常的函数之间的调用。

现在加入跳转函数,先来看一下跳转函数的man手册定义:
在这里插入图片描述
在这里插入图片描述
如果是在设置跳转点,那么返回值就是0,如果是从别处跳回来,那么返回值就为非0。

接下来我们将在上面的程序中,让函数 d 跳走,然后在函数 a 当中设置一个跳转点:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
可以看见直接跳转到了函数 a,然后程序直接执行结束了就。

资源的获取及控制

查看系统资源的命令还记得吗?
ulimit -a:
在这里插入图片描述

这里依然是提供两个函数,一个是getrlimit()用来获取资源总量,另外一个是setrlimit()用来设置资源总量。

在这里插入图片描述
在这里插入图片描述
可以从上图看到有个硬限制和软限制,软限制表示其只能在硬限制范围内活动,高不能高过硬限制;普通用户对自己某种资源的硬限制只能降低不能抬高,而对于root用户对于自己所用资源的软限制可以升高可以降低但高也不能高过自己的硬限制,对于自己的硬限制则可以升高可以降低。

  • 23
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux系统编程是指在Linux操作系统下进行程序开发的过程和技术。它包括了使用系统调用、编写应用程序、处理文件和目录、进程管理等一系列操作。 在Linux系统编程,可以使用系统调用来获取系统相关的信息,比如时间和日期。你可以使用time函数来获取当前的系统时间,date函数来获取当前的日期。这些函数可以帮助你获取到你所需要的系统信息。 此外,你可以使用Linux系统下的/proc虚拟文件系统来获取更详细的系统信息。在/proc目录下,每个进程都有一个对应的子目录,其包含了该进程的相关信息。你可以读取这些文件来获取进程的状态、文件描述符等详细信息。 在Linux系统编程,你可以使用system函数来执行shell命令。这个函数可以让你在程序方便地执行任意的shell命令。比如,你可以使用system("ls -la")来执行ls命令来列出当前目录下的所有文件文件夹。你也可以使用system("echo HelloWorld")来执行echo命令打印出HelloWorld。 除了上述内容,Linux系统编程还涉及到进程管理、文件和目录操作、进程通信等方面的内容。你可以使用fork函数创建子进程,使用exec函数执行新的程序,在程序之间进行进程通信等等。这些都是Linux系统编程常见的任务和技术。 总结起来,Linux系统编程是在Linux操作系统下进行程序开发的过程和技术,包括使用系统调用、处理文件和目录、进程管理、进程通信等一系列操作。通过使用系统调用和/proc虚拟文件系统,你可以获取到系统的相关信息。同时,使用system函数可以方便地执行shell命令。这些都是Linux系统编程常见的内容和技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在地球迷路的怪兽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值