系统编程--目录操作与重定向

目录操作

getcwd、chdir函数

作用

分别是获取当前工作目录、以及改变当前进程的工作目录

原型

在这里插入图片描述

目录与文件的关系

简介

在这里插入图片描述
首先明确:目录也是一个文件

其文件内容就是所有子文件的目录项(dentry),使用vim打开一个目录,也是显示其子文件的目录项

而其三个权限与文件的区别见上图

代码

在这里插入图片描述
测试:没有x权限就无法cd,首先使用ls -ld 目录名(若要查看一个文件的详细信息,是使用ls -l ,即没有d)

之后使用chmod 改变文件权限,a-x,是三组都减去x权限

最终,该目录没有x权限后,就无法cd了

opendir

man 3 卷(说明其不是一个系统调用,而是一个库函数(标准库))
而且返回值是DIR*,与文件的FILE*类似,且二者都无法查看其实现,所以说对于目录的这些操作与对文件的类似的操作是同级别的

函数原型

在这里插入图片描述
传入目录的路径(精确到目录本身)
在这里插入图片描述
返回值如果是NULL,那么就调用失败,设置errno

closedir

man 3 卷

函数原型

在这里插入图片描述

readdir

函数原型

在这里插入图片描述
在这里插入图片描述
该函数会返回一个dirent结构体,该结构体就是目录项,可以看到目录项中不仅有文件名、inode数(此处的inode我们一般也不用,而是使用“对文件其他操作”一栏中的stat函数传出的stat结构体),还有其他信息(只不过很少用的到)

在这里插入图片描述
返回值:如果到了文件尾,那么返回NULL,此时没出错,errno不会被设置
如果出错了,那么还是会返回NULL,但是此时errno会被设置

代码(实现ls功能)

使用opendir、closedir、readdir实现ls功能
在这里插入图片描述

需要注意的是,最终的结果会显示指定的目录的子文件之外,还会显示“.”、“…” 这两个被隐藏的文件,我们可以在代码中加以判断进行continue

总结

在这里插入图片描述

综合应用

目标

在这里插入图片描述
实现一个ls -R,也就是显示当前子文件的同时,如果子文件是一个目录,那么将其目录内的子文件也显示出来,依次类推,有目录就向内显示

思路

在这里插入图片描述
对于1,当argc是1时,说明没有传参,那么默认是传入 ./
2,特殊情况的处理:之后判断传入的第一次参数是文件还是目录,文件的话直接输出即可
3,若是目录
则打开目录,循环读取,读取时判读是否是文件,是文件,则打印
不是文件,则说明要进行递归读取,那么就调用步骤3即可,这里注意要拼接一下相对路径,因为已经来到了第二层,而该进程不会来到第二层,还是以argv[1]的视角来调用函数,所以,第二层调用opendir时,要先拼接上第一层的路径(即打开argv[1]中的哪个目录)

4,
在这里插入图片描述
而每个看起来空的目录,其内部都会有两个目录:“.”、“…”
所以,要加以判断防止出现无限递归

代码

头文件:
在这里插入图片描述

main:(步骤1)
在这里插入图片描述
如果agrc是1,说明没有输入参数,那么默认为“.”
否则,我们认为其输入了一个参数,传入isFile函数

isFile:(步骤2,对特殊情况进行处理 + 后续步骤3中每个循环步可以直接使用该函数:是文件则输出,是目录则递归)
在这里插入图片描述
传入一个name之后,拿到该“文件”(此处的文件是广义的,因为目录也是文件)的stat

之后判断他是否是一个目录,如果是,等待进行下一步操作

如果不是,那么输出其文件名和文件大小,而目录执行完if之后,也会执行到该输出文件,所以也会输出目录的大小(因为stat表示的“文件”,是广义的“文件”,其属性可以表示“狭义文件”,以及“目录”的属性)

read_dir:(步骤3)
在这里插入图片描述
注意no.9:对函数进行声明
no.24~no.26:对".“、”…"目录进行特殊处理,让其跳过

回调代码

将递归改为回调函数:

1、对read_dir,添加一个参数,这是一个函数指针,参数是char *(返回值和参数可能取决于所回调的函数,如下图第2步,isFile函数返回值是void 参数是char 星)
在这里插入图片描述
2、调用read_dir时,第二个参数要传入回调的函数名
在这里插入图片描述
3、在read_dir中,递归语句,改为回调函数:
func是一个函数指针,我们先解引用:*func,之后加上括号以防歧义,后面跟上括号进行参数的传入
在这里插入图片描述

回调函数的作用是:可以运行后,通过传参,传入不同的递归函数

重定向

命令行的重定向

在这里插入图片描述
重定向,就是将“要输出到屏幕”的内容,写到一个文件内

如何在程序中用代码实现呢:
其实写到屏幕。就是写到“标准输出”这个文件描述符里,所以,我们只要重点操作文件描述符即可实现重定向的功能

dup

函数原型

在这里插入图片描述
参数一:旧的已有的文件描述符
在这里插入图片描述
返回值:成功返回新的文件描述符,失败返回-1,设置errno

代码

在这里插入图片描述
使用dup,我们首先要有一个旧的文件描述符,想要有一个旧的文件描述符,我们就要打开一个文件,这样该文件才会有文件描述符,
旧的文件描述符是3,dup会返回一个新的文件描述符,是拷贝旧的文件描述符得到的,所以,newfd是4,是拷贝3得来的

可能会用于后续,我们使用dup2后,一个文件的文件描述符会丢失,我们可以使用dup先预存一个

dup2

函数原型

在这里插入图片描述
两个参数,参数一:旧的文件描述符 参数二:新的文件描述符
(但是此新非彼新,这个虽然称为新的文件描述符,实际上,这也是一个已有的,一个打开已经存在的文件所获得的已有的文件描述符)

作用:将旧的文件描述符赋值给新的文件描述符,并且返回新的文件描述符,原理图:
在这里插入图片描述
可以看到,拷贝文件描述符,只是拷贝文件描述符这个指针,所以拷贝完之后,相当于两个指针指向一个文件了

他和dup的区别:
dup是生成一个新的,目前不存在的文件描述符
dup2:是已有两个文件描述符,我们可以指定参数二的描述符拷贝参数一的描述符

dup无法指定新的描述符,而是按照文件描述符表的顺序进行生成
dup2是指定一个已有的文件描述符

代码dup2

在这里插入图片描述
打开两个文件,就可以得到两个文件描述符(注意,要以可读写的方式打开,不然文件描述符没有写的权限,是无法进行内容写入的,无法进行下面的测试)(追加写入的设置,也是在“打开文件时所传入的打开方式”来设置)

之后,将fd2拷贝fd1,也就是fd2现在指向跟fd1一样的文件

所以,我们下面向fd2写入内容,会写入到fd1文件内,效果如下:
在这里插入图片描述
out文件的内容:
在这里插入图片描述
因为这里的打开方式是普通的可写,而没有使用“追加”,所以,会从最开始进行覆盖写入。

输出重定向

在这里插入图片描述
上图的20行和22行,测试了输出重定向

我们想要实现输出重定向,就要把目标文件的文件描述符,拷贝给STDOUT_FILENO这个文件描述符,这样,一切向“屏幕输出”的内容,都会输出到目标文件内

使用fcntl函数来实现dup

代码

在这里插入图片描述
我们的fcntl,本来是用于修改文件的“阻塞非阻塞”属性,这里可以通过传参,来实现dup,当我们第二个参数传入F_DUPFD,第三个参数传入0,那么由于0被占用了,所以,就会拷贝第一个参数:旧的文件描述符,到最新的可用的文件描述符,返回新的fd,也就实现了dup的功能

使用fcntl函数来实现dup

代码

在这里插入图片描述
当我们第三个参数传入一个未被占用的,指定的文件描述符的时候,就会实现dup2的功能,将fd1拷贝给7
同时我们对7进行写入,会写到fd1中

总结

实际上,不管第三个参数传入0还是7,都是使用>=参数3的最小的可用的文件描述符,只不过0是百分百被占用的,而7是我们事先知道没被占用的,所以,只是根据不同的特性进行了模拟

二级目录

一级目录

二级目录

二级目录

二级目录

一级目录

二级目录

二级目录

二级目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值