学习视频链接
黑马程序员-Linux系统编程_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1KE411q7ee?p=65&spm_id_from=pageDriver
目录
一、getcwd 和 chdir 函数
1.1 getcwd函数
1.2 chdir 函数
1.3 测试案例
二、文件和目录权限
2.1 vim查看目录
2.2 目录权限和文件权限区别
三、opendir、readdir、closedir函数
3.1 opendir 函数
3.2 readdir
3.3 closedir 函数
3.4 测试案例
四、案例:递归遍历指定目录
4.1 Linux遍历目录命令
4.2 思路
4.3 代码
4.4 实现另外一些功能
五、重定向 dup 和 dup2 函数
5.1 Linux 自带重定向
5.2 dup 和 dup2 函数
5.3 dup2实现重定向效果
六、fcntl函数实现dup2
6.1 函数
6.2 操作
1、作用
获取进程当前工作目录(卷3 标库函数:man 3 getcwd)
2、char *getcwd(char *buf, size_ t size);
成功 buf 中保存当前进程工作目录位置
失败返回 NULL
1、作用
改变当前进程的工作目录。
2、int chdir(const char *path);
成功 返回 0
失败 返回 -1,设置 errno 为相应的值
获取及修改当前进程的工作目录,并打印至屏幕
1、目录内容:
目录文件也是 “文件”。其文件内容是该目录下所有子文件的目录项 dentry。可以尝试用 vim 打开一个目录。
2、用 vim 打开目录
下面 imp_cd.c 和 a 是目录项
r | w | x | |
文件 | 文件的内容可以被查看 cat、more、less... |
内容可以被修改 vi、>、... |
可以运行产生一个进程 ./文件名 |
目录 | 目录可以被浏览 ls、tree... |
创建、删除、修改文件 mv、touch、mkdir... |
可以被打开、进入 |
修改文件夹权限
1、作用
根据传入的目录名打开一个目录(库函数,不是系统调用,查看这个函数在第三卷 man 3 opendir)
2、DIR *opendir(const char *name);
成功返回指向该目录结构体指针,失败返回 NULL
参数支持相对路径、绝对路径两种方式:例如:打开当前目录:① getcwd(),opendir() ② opendir(".");
1、作用
读取目录(库函数)
2、struct dirent *readdir(DIR *dirp);
成功返回目录项结构体指针
失败返回 NULL,设置 errno 为相应值
需注意返回值,读取数据结束时也返回 NULL 值,所以应借助 errno 进一步加以区分
3、struct 结构体
其成员变量重点记忆两个:d_ino、 d_name。实际应用中只使用到 d_name
因为 d_name 数组最大为 256,所以目录项限定为 255(名字 + \n 要小于 256)
1、作用
关闭打开的目录。
2、int closedir(DIR *dirp);
成功返回 0
失败返回 -1,设置 errno 为相应值
1、使用上述三个函数实现一个 ls 的效果
2、C语言代码
3、编译执行
4、不显示 .. 和 .
1、简易版本
#include
#include
#include
#include
#include
#include
void isFile(char *name)
{
int ret = 0;
struct stat sb;
ret = stat(name, &sb);
if (ret == -1) {
perror("stat error");
return;
}
if (S_ISDIR(sb.st_mode)) { // 如果是文件夹,进行的操作
}
printf("%s\t%ld\n", name, sb.st_size);
return;
}
int main(int argc, char *argv[])
{
if (argc == 1) { // 没有传入文件的时候 ./ls-R,默认传入 ./ls-R 。
isFile(".");
}
else {
isFile(argv[1]);
}
return 0;
}
2、完善
#include
#include
#include
#include
#include
#include
#include
void isFile(char *name);
void read_dir(char *dir);
// 打开、读取目录,处理目录
void read_dir(char *dir)
{
char path[256]; // 存储拼接后的文件绝对路径
DIR *dp;
struct dirent *sdp;
dp = opendir(dir);
if (dp == NULL) {
perror("opendir error");
return;
}
// 读取目录项
while ((sdp = readdir(dp)) != NULL) {
if (strcmp(sdp->d_name, ".") == 0 || strcmp(sdp->d_name, "..") == 0) {
continue;
}
// 目录项本身不可访问,需要拼接 目录/目录项
sprintf(path, "%s/%s", dir, sdp->d_name);
// 判断文件类型,目录递归进入,文件显示名字/大小
isFile(path);
}
closedir(dp);
return;
}
void isFile(char *name)
{
int ret = 0;
struct stat sb;
// 获取文件属性,判断文件类型
ret = stat(name, &sb);
if (ret == -1) {
perror("stat error");
return;
}
// 如果是目录文件就进行下面的操作
if (S_ISDIR(sb.st_mode)) {
read_dir(name);
}
// 是普通文件,显示名字/大小
printf("%10s\t%ld\n", name, sb.st_size);
return;
}
int main(int argc, char *argv[])
{
// 判断命令行参数
if (argc == 1) { // 没有传入文件的时候 ./ls-R,默认传入 ./ls-R 。
isFile(".");
}
else {
isFile(argv[1]);
}
return 0;
}
3、优化
(1) 根据警告中的内容,可以做一个长度判断
如果拼接长度大于 256 要做一个错误处理
(2) 修改为主调和回调函数(涉及到函数指针)
统计目录及其子目录中普通文件的个数
重定向 > :cat 文件名 > 文件名
可以把本来准备写到屏幕上的东西,现在写到文件里面去
1、函数原型
int dup(int oldfd);
int dup2(int oldfd, int newfd);
当调用 dup 和 dup2 函数时,内核在进程中创建一个新的文件描述符,此描述符是当前可用文件描述符的最小数值,这个文件描述符指向 oldfd 所拥有的文件表项。这个文件描述符作为函数的返回值被返回出来。
若有错误则返回 -1,errno 会存放错误代码
2、简单使用
1、实现原理
int dup2(int oldfd, int newfd);
dup2 函数的妙用就是让 newfd 文件描述符指向 oldfd
现在我们可以让指向屏幕上的东西不再指向屏幕,而是指向文件。
在屏幕上打印,等同于写入文件
2、代码
3、编译运行,查看结果
int fcntl(int fd, int cmd, ...)
cmd 传入相应的宏:F_DUPFD
参数3:文件描述符被其他文件占用时,返回最小可用的文件描述符。未被占用就返回 >= 该值的文件描述符
因为文件描述符 0 1 2 3 都被占了,所以 newfd 返回 4,文件描述符 7 没有被占,所以 newfd2 返回 7
最终我们使用 newfd2 指向 fd1 文件描述符指向对象,并且使用 newfd2 进行了写操作