一 目录流

1 目录相关系统调用

1.1 改变文件权限

这个就和shell命令中的chmod是相同的,在C语言也可以使用同名函数来改变文件的权限,在linux环境下,chmod是一个系统调用函数,也就是POSIX库的函数名。

1
2
#include<sys/stat.h>
int chmod(const char * path,mode_t mode);

形参:pathname是文件或目录的路径字符串、mode是要设置的新权限,要使用权限数字表示法,即八进制数。

返回值:成功chmod返回0,失败返回-1。

1.2 获取当前工作目录

类似于shell命令中的pwd,C语言中的getcwd函数,也就是POSIX库函数,用于获取当前工作目录的绝对路径名称。

1
2
#include<unistd.h>
char * getcwd(char * buf,size_t size);

形参buf是存放当前工作目录的字符串的字符数组、size就是这个数组的大小

返回值:成功getcwd就会返回指向buf的指针,buf中包含了当前工作目录的绝对路径。

​ 失败返回NULL,并设置 errno 以指示错误的原因。出错的原因普遍是buf数组过小,无法容纳整个工作目录绝对路径字符串

1.3 该表当前工作目录

chdir函数是一个Linux系统调用函数,它的作用是改变当前工作目录。

1
2
#include <unistd.h>
int chdir(const char *path);

形参:

  1. path: 是一个指向字符数组的指针,这个数组包含了新工作目录的路径。
  2. 路径可以是绝对的(从根目录开始,例如 “/usr/local/bin”)或相对的(相对于当前工作目录,例如 “../docs”)。

返回值:

  1. 成功时,chdir 返回 0。
  2. 失败时,返回 -1,并设置全局变量 errno 以指示错误的原因。比较常见的错误,比如目标目录不存在、权限问题、目标不是目录等

1.4 创建目录

mkdir(make directory)系统调用函数用于创建一个新目录。

1
2
3
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);

形参:

  1. pathname: 要创建的目录的路径名。可以是绝对路径也可以是相对路径名。
  2. mode: 设置新目录的权限。这是一个八进制数,类似于 chmod 的权限设置(例如,0775)。注意,最终的权限还会受到进程的 umask 设置的影响。

返回值:

  1. 成功时,mkdir 返回 0。
  2. 失败时,返回 -1,并设置 errno 以指示错误的原因。常见错误比如目录已存在等

1.5 删除目录

rmdir(remove directory)系统调用函数用于删除一个空目录,注意只能删除空目录。

1
2
#include <unistd.h>
int rmdir(const char *pathname);

形参pathname: 要删除的空目录的路径名。

返回值:

  1. 成功时,rmdir 返回 0。
  2. 失败时,返回 -1,并设置 errno 以指示错误的原因。常见的错误原因有目录非空,不存在或无权限等。

2 目录流相关POSIX库函数

目录流可以用下图来理解

目录流-模型图

目录流指针,他已开就会指向当前目录文件的第一个目录项,并可以向后移动.

2.1 打开目录流

opendir函数,用于打开一个目录流以读取其中的目录项。

使用 opendir 打开一个目录时,系统会创建一个目录流,并返回一个指向该流的DIR指针。

该目录流指针一开始指向目录项第一个,然后程序可以通过函数来移动这个目录项指针,从而实现对目录的遍历和管理。

1
2
3
#include <dirent.h>     // dirent是directory entry的简写,就是目录项的意思
#include <sys/types.h>
DIR *opendir(const char *name);

形式参数:name: 字符串,代表要打开的目录的路径。

返回值:

  1. 成功时,返回指向 DIR 类型的指针,即目录流的指针
  2. 失败时,返回 NULL 并设置 errno 以指示错误的原因。常见的失败原因,比如目录没有权限打开、目录不存在等。

2.2 关闭目录流

关闭目录流。这样做可以释放分配给目录流的资源,避免内存泄漏。

1
2
3
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);

形式参数:dirp: 由 opendir 返回的目录流指针。

返回值:

  1. 成功:返回0
  2. 失败时,返回 -1 并设置 errno 以指示错误的原因。常见的错误原因就是乱传指针,传入的指针不是打开的目录流指针。

2.3 读目录流

使用 opendir 打开一个目录流后,可以使用 readdir 依次读取目录中的每个条目,直到目录中没有更多条目为止。

1
2
#include <dirent.h>
struct dirent *readdir(DIR *dirp);

形式参数:dirp: 由 opendir 返回的目录流指针。

返回值:

  1. 返回值: 成功时,返回指向 struct dirent 结构体对象的指针,这个结构体当中包含了目录下文件和子目录的信息(如文件名等)。
  2. 当目录中没有更多条目时返回 NULL
  3. 当函数出错时该函数也会返回NULL。但只要传给函数的指针是一个打开的目录流指针,该函数一般不会出错,所以可以把返回NULL作为读完目录流的标记,而不需要做错误处理。

2.3.1 dirent结构体

dirent是词组directory entry的缩写,也就是目录项的意思。所以dirent结构体,就是当前目录下的某个文件/子目录的目录项结构体,这个结构体中会存储当前目录下的某个文件/子目录的信息。

dirent结构体的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
// dirent是directory entry的简写,就是目录项的意思
struct dirent {
// 此目录项的inode编号,目录项中会存储文件的inode编号。一般是一个64位无符号整数(64位平台)
ino_t d_ino;
// 到下一个目录项的偏移量。可以视为指向下一个目录项的指针(近似可以看成链表),一般是一个64位有符号整数
off_t d_off;
// 此目录项的实际大小长度,以字节为单位(注意不是目录项所表示文件的大小,也不是目录项结构体的大小)
unsigned short d_reclen;
// 目录项所表示文件的类型,用不同的整数来表示不同的文件类型
unsigned char d_type;
// 目录项所表示文件的名字,该字段一般决定了目录项的实际大小。也就是说文件名越长,目录项就越大
char d_name[256];
};

用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <cstddef>
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <iostream>
int main()
{
DIR* dir = opendir(".");
if (dir == NULL)
{
std::cerr << "Error: could not open directory." << std::endl;
return -1;
}
struct dirent* entry;
while ((entry = readdir(dir)) != NULL)
{
std::cout << entry->d_ino << std::endl;
std::cout << entry->d_reclen << std::endl;
std::cout << entry->d_type << std::endl;
std::cout << entry->d_name << std::endl;
}
closedir(dir);
return 0;
}

2.4 移动目录流指针

2.4.1 seekdir和telldir函数

seekdir 函数用于设置目录流指针的当前位置,但和文件流的fseek函数不同的是:该函数没有参照点的概念,只能通过 telldir 函数提供的返回值来进行指针的移动。

即:必须先用telldir函数记录指针的位置,然后才能够使用seekdir返回记录的位置!

telldir函数的声明如下:

1
2
#include <dirent.h>
long telldir(DIR *dirp);

形式参数:dirp 是由 opendir 返回的目录流指针。

返回值:

  1. 返回值是目录流指针当前读取位置的标记,是一个长整型值。该返回值需要给seekdir函数使用,一般不作其它用途。
  2. 该函数如果出错,会返回-1。但只要正确传递已打开的目录流指针,该函数一般不会出错,所以一般不做错误处理。

seekdir函数的声明如下:

1
2
#include <dirent.h>
void seekdir(DIR *dirp, long loc);

形式参数:

  1. dirp 是由 opendir 返回的目录流指针。
  2. loc 是由 telldir 返回的位置标记。

返回值:

  1. 该函数没有返回值,这说明函数的设计者认为该函数不需要错误处理。
  2. 该函数必须传入由telldir函数获取的位置,在移动指针的过程中是纯粹的内存操作,也不涉及内存数据的读写操作,本身是非常安全的,不会出错,也确实不需要错误处理。

2.4.2 倒带目录流

rewinddir 函数重置目录流的位置到开始处,类似于文件流中的 rewind 函数。

1
2
#include <dirent.h>
void rewinddir(DIR *dirp);

形式参数:dirp 是由 opendir 返回的目录流指针。

**返回值:**没有返回值。说明函数的设计者认为,该函数不会出错,也不需要进行错误的处理。

使用 rewinddir 可以使得目录流回到初始位置,这样下一次调用 readdir 将返回目录中的第一个条目

3 stat系统调用函数

stat是一个系统调用函数,stat 用于获取指定文件的相关详细信息,主要包括各种元数据信息。

1
2
#include <sys/stat.h>
int stat(const char *path, struct stat *buf);

形式参数:

  1. path:这是一个指向字符数组的指针,代表要获取信息的文件的路径名。
  2. buf:这是一个指向 struct stat 结构的指针,用于存储获取到的path文件的信息。

返回值:

  1. 成功:返回 0
  2. 失败:返回 -1,并且 errno 被设置以指示错误的原因。常见的出错原因有文件不存在、没有权限等。