标签: info 文件 编程 int 常见 strcat char 指令 文件夹
ls -l完整实现
1. 文件操作
opendir() : 用于打开一个目录流,并返回一个指向DIR结构的指针。如果打开失败,返回NULL。
函数名 opendir 头文件 #include<sys/types.h>#include<dirent.h> 函数原型 DIR * opendir(const char * name); 功能 打开 name 指定的目录 参数说明 name:要操作的目录名;2. DIR * 详细内容请查看相关数据结构体 说明部分 返回值 成功,返回DIR* 目录流,否则返回NULL,并将错误码存放于errno 里
readdir() : 读取目录流中的下一个目录项。每次调用时,它返回一个指向struct dirent结构的指针,该结构包含了目录项的信息。
函数名 readdir 头文件 #include<sys/types.h>#include<dirent.h> 函数原型 struct dirent * readdir(DIR * dir); 功能 遍历文件目录 参数说明 1.dir:要操作的目录流指针;struct dirent * 详见相关数据结构体说明部分 返回值 成功:用于描述一个目录项信息的指针,隐藏的位置指针会指向下一个目录项错误发生或读取到目录尾则返回NULL并将错误码存入 errno 中
closedir() : 关闭由opendir()打开的目录流。
函数名 closedir 头文件 #include<sys/types.h> #include<dirent.h> 函数原型 int closedir(DIR *dir); 功能 关闭参数dir所指的目录流 参数说明 dir:要操作的目录流指针; 返回值 成功,返回0,失败返回-1,并将错误码放入 errno
struct dirent : 这是一个结构体,包含了目录项的信息,如文件名(d_name)和文件类型(d_type)。
struct __dirstream
{
void *__fd; /* `struct hurd_fd' pointer for descriptor. */
char *__data; /* Directory block. */
int __entry_data; /* Entry number `__data' corresponds to. */
char *__ptr; /* Current pointer into the block. */
int __entry_ptr; /* Entry number `__ptr' corresponds to. */
size_t __allocation; /* Space allocated for the block. */
size_t __size; /* Total valid data in the block. */
__libc_lock_define (, __lock) /* Mutex lock for this structure. */
};
typedef struct __dirstream DIR;
struct dirent
{
long d_ino; /* 索引节点号 */
off_t d_off; /* 在目录文件中的偏移 */
unsigned short d_reclen; /* 文件纪录长度 */
unsigned char d_type; /* 文件类型 */
char d_name[NAME_MAX+1]; /* 文件名 */
}
2. 文件类型判断
d_type : 在struct dirent结构体中,d_type字段用于表示文件类型。常见的类型有DT_REG(普通文件)、DT_DIR(目录)、DT_LNK(符号链接)等。注意,直接使用数字(如4)来判断文件类型是不推荐的,应该使用宏定义(如DT_DIR)来提高代码的可读性和可移植性。
enum
{
DT_UNKNOWN = 0, //未知
DT_FIFO = 1, //管道文件
DT_CHR = 2, //字符设备文件
DT_DIR = 4, //目录文件
DT_BLK = 6, //块设备文件
DT_REG = 8, //一般文件
DT_LNK = 10, //链接文件
DT_SOCK = 12, //套接字文件
DT_WHT = 14
};
注意: d_type 虽然是个unsigned char
类型,但实际取值如上
3. 文件状态信息的获取
stat() : 该函数用于获取文件的状态信息,并将这些信息填充到一个stat结构体中。这个结构体包含了文件的多种属性,如大小(st_size)、权限(st_mode)、链接数(st_nlink)、最后修改时间(st_mtime)等。
struct stat
{
dev_t st_dev; //文件设备编号
ino_t st_ino; //文件inode节点号
mode_t st_mode; //文件类型,访问权限等
nlink_t st_nlink; //文件的连接数
uid_t st_uid; //文件所有者的用户ID
gid_t st_gid; //文件所有者对应的组ID
dev_t st_rdev; //若文件为设备文件,则表示设备编号
off_t st_size; //文件大小,对应的文件字节数
blksize_t st_blksize; //文件系统的 I/O 缓冲区大小
blkcnt_t st_blocks; //占用文件区块数量,每一区块512 字节
time_t st_atime; //文件最后一次被访问的时间
time_t st_mtime; //文件内容最后一次被修改的时间
time_t st_ctime; //最后一次改变时间(属性改变)
};
函数名 stat 头文件 #include <fcntl.h> #include <unistd.h>#include <sys/types.h> #include <sys/stat.h> 函数原型 int stat(const char path, struct stat buf)int fstat(int fd, struct stat *buf); 功能 获取文件状态, 参数说明 path:要操作的文件名或路径;buf:指向stat 结构体的指针,用来获取文件状态信息:3. fd:文件描述符 注:struct stat 见下页 stat 函数用来获取未打开的文件状态信息,fstat 函数用来获取打开的文件状态信息 返回值 成功:返回 0出错:返回 -1,并将错误码存入 errno 中
S_ISDIR() : 这是一个宏,用于判断文件是否为目录。它接受一个文件模式(mode)作为参数,如果文件是目录,则返回非零值。
4. 时间处理
time() : 获取当前时间(自1970年1月1日以来的秒数)。localtime() : 将time_t类型的时间转换为本地时间(struct tm类型)。struct tm : 这是一个结构体,包含了时间的详细信息,如年(tm_year)、月(tm_mon)、日(tm_mday)、小时(tm_hour)、分钟(tm_min)等。
5. 字符串操作
strcpy() : 复制字符串。strcat() : 连接字符串。strtok() : 分割字符串。它根据指定的分隔符来分割字符串,并返回分割后的子字符串。snprintf() : 格式化字符串并输出到指定的字符数组中。与sprintf()相比,snprintf()允许指定输出缓冲区的大小,从而避免了缓冲区溢出的风险。memset() : 将一段内存区域的内容全部设置为指定的值(通常是0)。
6. 错误处理
perror() : 打印描述最近一次库函数调用错误的字符串。它通常与检查函数返回值是否为NULL或-1等错误条件一起使用。
7. 注意事项
缓冲区大小 : 在使用字符串操作函数(如snprintf()、strcat())时,要注意缓冲区的大小,以避免缓冲区溢出。宏定义与数字 : 在判断文件类型时,应使用宏定义(如DT_DIR)而不是数字,以提高代码的可读性和可移植性。错误处理 : 在进行文件操作时,要检查函数的返回值,以处理可能的错误情况。
header.h
#ifndef _HEARD_H
#define _HEARD_H
// 常用头文件, remove, rename
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// access, read, write, lseek, stat,lstat, rmdir, fork
#include <unistd.h>
// open, lseek, stat,lstat, getpwuid, opendir, closedir, mkdir,
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// mmap, munmap
#include <sys/mman.h>
// getpwuid
#include <pwd.h>
#include <grp.h>
// time
#include <time.h>
// opendir,readdir, closedir
#include <dirent.h>
typedef struct stat Stat;
// 1.获取文件的类型
int getFileType(Stat *pstat, char *info);
// 2.获取文件所属用户的权限
int getOwnerPrem(Stat *pstat, char *info);
// 3.获取同组其他用户的权限
int getgrPrem(Stat *pstat, char *info);
int getgrrPrem(Stat *pstat, char *info);
// 5.获取链接数量
int getLinkNum(Stat *pstat, char *info, const char *file);
// 6.获取文件的所属名称
int getOwnerName(Stat *pstat, char *info);
// 7.文件所属用户的组名
int getGroupName(Stat *pstat, char *info);
// 8.获取文件的大小
int getFileSize(Stat *pstat, char *info);
// 9.获取文件最后修改的时间
int getModifyTime(Stat *pstat, char *info);
// 10.获取文件的名称
int getFileName(const char *filePath, char *info);
int getOwnerGroupName(Stat *pstat, char *info);
#endif
myls.c
#include "header.h"
// 1.获取文件的类型
int getFileType(Stat *pstat, char *info)
{
// 获取结构体成员的值
mode_t mode = pstat->st_mode;
printf("mode: %o\n", mode);
// 判断文件类型
if (S_ISLNK(mode))
info[0] = 'l';
else if (S_ISREG(mode))
info[0] = '-';
else if (S_ISDIR(mode))
info[0] = 'd';
else if (S_ISCHR(mode))
info[0] = 'c';
else if (S_ISBLK(mode))
info[0] = 'b';
else if (S_ISSOCK(mode))
info[0] = 's';
else if (S_ISFIFO(mode))
info[0] = 'p';
return 0;
}
int getOwnerPrem(Stat *pstat, char *info)
{
// 获取结构体成员的值
mode_t mode = pstat->st_mode; // 40542
/*
100 000 101 100 010
& 000 000 111 000 000
---------------------------
000 000 101 000 000
0 0 5 0 0
*/
// 判断文件类型
// int perm = mode & 00700; drwx0000000000000000
int perm = mode & S_IRWXU;
if (perm == S_IRWXU)
strcat(info, "rwx");
else if (perm == S_IRUSR)
strcat(info, "r--");
else if (perm == S_IWUSR)
strcat(info, "-w-");
else if (perm == S_IXUSR)
strcat(info, "--x");
else if (perm == (S_IRUSR | S_IWUSR))
strcat(info, "rw-");
else if (perm == (S_IXUSR | S_IWUSR))
strcat(info, "-wx");
else if (perm == (S_IXUSR | S_IRUSR))
strcat(info, "r-x");
else
strcat(info, "---");
return 0;
}
// 用户组权限
int getgrPrem(Stat *pstat, char *info)
{
// 获取结构体成员的值
mode_t mode = pstat->st_mode; // 40542
printf("用户组权限\n");
int perm = mode & S_IRWXG; // 获取用户组权限位
switch (perm)
{
case S_IRWXG:
strcat(info, "rwx");
break;
case S_IRGRP:
strcat(info, "r--");
break;
case S_IWGRP:
strcat(info, "-w-");
break;
case S_IXGRP:
strcat(info, "--x");
break;
case (S_IRGRP | S_IWGRP):
strcat(info, "rw-");
break;
case (S_IXGRP | S_IWGRP):
strcat(info, "-wx");
break;
case (S_IXGRP | S_IRGRP):
strcat(info, "r-x");
break;
default:
strcat(info, "---");
break;
}
// 返回一些值,这里假设返回1表示成功
return 1;
}
// 其他用户
int getgrrPrem(Stat *pstat, char *info)
{
// 获取结构体成员的值
mode_t mode = pstat->st_mode; // 40542
printf("其他用户权限\n");
int perm = mode & S_IRWXO; // 获取用户组权限位
switch (perm)
{
case S_IRWXO:
strcat(info, "rwx");
break;
case S_IROTH:
strcat(info, "r--");
break;
case S_IWOTH:
strcat(info, "-w-");
break;
case S_IXOTH:
strcat(info, "--x");
break;
case (S_IROTH | S_IWOTH):
strcat(info, "rw-");
break;
case (S_IXOTH | S_IWOTH):
strcat(info, "-wx");
break;
case (S_IXOTH | S_IROTH):
strcat(info, "r-x");
break;
default:
strcat(info, "---");
break;
}
// 返回一些值,这里假设返回1表示成功
return 1;
}
// 6.获取文件的所属名称
int getOwnerName(Stat *pstat, char *info)
{
// 获取所属用户的uid
uid_t uid = pstat->st_uid;
// 调用函数通过用户id获取用户名称
struct passwd *passwd_p = getpwuid(uid);
// 获取结构体成员中的name
char *uname = passwd_p->pw_name;
strcat(info, " ");
// 将用户名拼接到字符串中
strcat(info, uname);
return 0;
}
// 7.获取文件所属组名称
int getOwnerGroupName(Stat *pstat, char *info)
{
// 获取所属组的gid
gid_t gid = pstat->st_gid;
// 调用函数通过组id获取组信息
struct group *grp_p = getgrgid(gid);
if (grp_p == NULL)
{
strcat(info, " [unknown group]");
return -1; // 返回错误码表示失败
}
// 获取结构体成员中的组名
char *gname = grp_p->gr_name;
// 在info字符串中添加空格和组名
strcat(info, " ");
strcat(info, gname);
return 0;
}
// 获取文件夹中子的数量
int getSubCount(const char *file)
{
// 统计变量
int count = 0;
// 打开文件夹
DIR *dir = opendir(file);
if (dir == NULL)
{
perror("opendir failed");
return -1;
}
// 遍历读取子
struct dirent *subDir = NULL;
while (subDir = readdir(dir))
{
// 判断子是文件夹
if (subDir->d_type == 4)
// if (subDir->d_type == DT_DIR)
{
// 统计子文件夹的数量
count++;
}
}
// 关闭文件夹
closedir(dir);
return count;
}
// 5.获取链接数量: 文件显示子文件夹的数量,文件显示硬连接的数量
int getLinkNum(Stat *pstat, char *info, const char *file)
{
// 判断文件的类型是不是文件夹
if (S_ISDIR(pstat->st_mode))
{
// 是文件夹,获取子文件夹的数量--稍后实现
int count = getSubCount(file);
if (count == -1)
{
return -1;
}
char buf[10] = {0};
snprintf(buf, 10, " %d ", count);
strcat(info, buf);
}
else
{
// 是文件,获取文件的链接数量
nlink_t num = pstat->st_nlink;
// 将基本类型的数据转换成字符串用sprintf
// 定义字符数组用户存储转换后的结果
char buf[10] = {0};
// sprintf(buf, "num=%lu", num); 相比snprintf不安全,有越界的风险
snprintf(buf, 10, " %lu ", num);
strcat(info, buf);
}
return 0;
}
// 8.获取文件的大小
int getFileSize(Stat *pstat, char *info)
{
off_t size = pstat->st_size;
// 定义字符数组用户存储转换后的结果
char buf[10] = {0};
snprintf(buf, 10, " %ld ", size);
strcat(info, buf);
return 0;
}
// 9.获取文件最后修改的时间: 如果是当年的就显示时间,如果是往年的就显示年份
int getModifyTime(Stat *pstat, char *info)
{
// 获取当前时间
time_t curTime = time(NULL);
// 根据当前秒值获取日历时间
struct tm *tm = localtime(&curTime);
// 获取当前的年份
int curYear = tm->tm_year;
// 从文件状态中获取最后修改的时间
time_t modifyTime = pstat->st_mtime;
struct tm *m_tm = localtime(&modifyTime);
// 定义字符串用于拼接日期和时间
char buf[20] = {0};
// 判断是否是当年
if (m_tm->tm_year == curYear)
{
// 当年: x月 x日 hh:mm
snprintf(buf, 20, " %d月 %d日 %02d:%02d ", m_tm->tm_mon + 1, m_tm->tm_mday, m_tm->tm_hour, m_tm->tm_min);
}
else
{
// 往年:x月 x日 yyyy
snprintf(buf, 20, " %d月 %d日 %d ", m_tm->tm_mon + 1, m_tm->tm_mday, m_tm->tm_year + 1900);
}
// 将日期追加到info中
strcat(info, buf);
return 0;
}
// 10.获取文件的名称 ~/aa.txt
int getFileName(const char *filePath, char *info)
{
// 因为filePath被const修饰,并且这个字符串是控制台传入的,所以它具备不可修改的特性
// 所以定义数组转存文件路径
char str[100] = {0};
strcpy(str, filePath);
// 截取字符串--strtok
char *subStr = strtok(str, "/");
// 定义数组存储截取到的字符串
char lastStr[50] = {0};
while (subStr != NULL)
{
memset(lastStr, 0, 50);
strcpy(lastStr, subStr);
subStr = strtok(NULL, "/");
}
// lastStr中存储的就是文件名
strcat(info, " ");
strcat(info, lastStr);
}
main.c
#include <stdio.h>
#include "header.h"
// 添加一个函数来遍历目录并打印每个文件的信息
void print_directory_contents(const char *dirpath)
{
DIR *dir = opendir(dirpath);
if (!dir)
{
perror("opendir failed");
return;
}
struct dirent *entry;
char path[1024];
struct stat statbuf;
while ((entry = readdir(dir)) != NULL)
{
// 跳过 "." 和 ".." 目录项
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
{
continue;
}
snprintf(path, sizeof(path), "%s/%s", dirpath, entry->d_name);
// 使用lstat而不是stat,因为我们要保留符号链接的信息
if (lstat(path, &statbuf) == -1)
{
perror("lstat failed");
continue;
}
// 为每个文件分配一个足够大的缓冲区来存储信息
char info[256] = {0};
// 获取并打印文件信息
getFileType(&statbuf, info);
getOwnerPrem(&statbuf, strcat(info, " ")); // 注意:这里使用strcat来追加字符串,确保info有足够的空间
// ... (省略其他权限和信息的获取,因为它们应该类似于下面的示例)
getLinkNum(&statbuf, strcat(info, " "), path);
getOwnerName(&statbuf, strcat(info, " "));
// 3.获取同组用户的权限---自学
getgrPrem(&statbuf, strcat(info, " "));
// 4.获取不同组的其他用户权限---自学
getgrrPrem(&statbuf, strcat(info, " "));
getOwnerName(&statbuf, strcat(info, " "));
// 8.获取文件的大小
getFileSize(&statbuf, strcat(info, " "));
// 9.获取文件最后修改的时间
getModifyTime(&statbuf, strcat(info, " "));
// 获取并追加文件名(应该在最后做,因为它会覆盖info缓冲区的末尾部分)
getFileName(entry->d_name, info + strlen(info)); // 这里不需要再strcat一个空格,因为getFileName应该自己处理
// 打印文件信息
puts(info);
}
closedir(dir);
}
int main(int argc, char const *argv[])
{
if (argc < 2)
{
puts("缺少参数");
return -1;
}
print_directory_contents(argv[1]);
return 0;
}
rm -r 实现
1. 文件系统操作
opendir
函数
原型 :DIR *opendir(const char *name);
功能 :打开一个目录流,并返回一个指向 DIR
结构体的指针,用于后续读取目录内容。参数 :name
是目录的路径。返回值 :成功时返回指向 DIR
结构体的指针,失败时返回 NULL
。
readdir
函数
原型 :struct dirent *readdir(DIR *dirp);
功能 :从目录流 dirp
中读取下一个目录项。参数 :dirp
是 opendir
返回的目录流指针。返回值 :指向 dirent
结构体的指针,包含目录项的信息。如果到达目录末尾或出错,返回 NULL
。
closedir
函数
原型 :int closedir(DIR *dirp);
功能 :关闭目录流。参数 :dirp
是 opendir
返回的目录流指针。返回值 :成功时返回 0
,失败时返回 -1
。
rmdir
函数
原型 :int rmdir(const char *pathname);
功能 :删除一个空目录。参数 :pathname
是要删除的目录的路径。返回值 :成功时返回 0
,失败时返回 -1
。
函数名 rmdir 头文件 #include <unistd.h> 函数原型 int rmdir(const char * dirname); 功能 删除一个空目录 参数说明 dirname:要操作的目录名; 返回值 成功:返回0出错:返回 -1,并将错误码存入 errno 中
remove
函数
原型 :int remove(const char *pathname);
功能 :删除一个文件。参数 :pathname
是要删除的文件的路径。返回值 :成功时返回 0
,失败时返回 -1
。
函数名 remove 头文件 #include <stdio.h> 函数原型 int remove(const char * pathname); 功能 删除一个文件或者目录,当pathname为一个文件则调用unlink来删除,如果是一个目录,则调用rmdir 来删除。 参数说明 pathname:要操作的文件或者目录名; 返回值 成功:返回0出错:返回 -1,并将错误码存入 errno 中
2. 字符串操作
strcmp
函数
原型 :int strcmp(const char *s1, const char *s2);
功能 :比较两个字符串。参数 :s1
和 s2
是要比较的两个字符串。返回值 :若 s1
和 s2
字符串相等,则返回 0
;若 s1
小于 s2
,则返回负数;若 s1
大于 s2
,则返回正数。
snprintf
函数
原型 :int snprintf(char *str, size_t size, const char *format, ...);
功能 :将格式化的数据写入字符串。参数 :str
是目标字符串的指针,size
是目标字符串的大小,format
是格式化字符串,...
是可变参数列表。返回值 :写入的字符数(不包括终止的空字符)。如果返回值大于或等于 size
,则输出字符串被截断。
3. 递归算法
递归是一种在函数内部调用自身的编程技巧。在这个例子中,myrm
函数使用递归算法来删除目录及其所有内容。递归的基本思想是将问题分解为更小的子问题,直到达到一个简单的情况(递归基准情况),可以直接解决。在这个例子中,递归基准情况是目录为空,这时可以直接删除目录。对于非空目录,函数会遍历目录中的每个条目,如果是文件则删除文件,如果是子目录则递归调用自身删除子目录
mian.c
#include <stdio.h>
#include "header.h"
// 定义函数:判断指定的文件夹是否为空
// 返回0(假)表示文件夹不为空, 1(真)表示文件夹为空
int dirIsEmpty(char const *dir)
{
int flag = 1;
// 打开文件夹
DIR *dir_p = opendir(dir);
// 循环读取文件夹中的子
struct dirent *p = NULL;
while (p = readdir(dir_p))
{
// 过滤文件夹中的两个隐藏文件夹:.和..
if (strcmp(p->d_name, ".") == 0 || strcmp(p->d_name, "..") == 0)
{
continue;
}
flag = 0;
break;
}
closedir(dir_p);
return flag;
}
// 定义函数:根据给定文件夹的路径递归删除文件夹中的所有内容
void myrm(char const *dir)
{
// 递归的出口---当文件夹为空
if (dirIsEmpty(dir))
{
// 文件夹为空,删除当前文件夹,并返回
rmdir(dir);
return;
}
// 递归的规律: 当前文件夹中的子是文件还是文件夹,如果是文件就删除,如果是文件夹就递归调用
// 打开当前文件夹
DIR *dir_p = opendir(dir);
struct dirent *p = NULL;
while (p = readdir(dir_p))
{
// 过滤文件夹中的两个隐藏文件夹:.和..
if (strcmp(p->d_name, ".") == 0 || strcmp(p->d_name, "..") == 0)
{
continue;
}
// 判断当前子是文件还是文件夹
// if (p->d_type == DT_DIR)
if (p->d_type == 4)
{
// 子是文件夹
char sub_dir[100] = {0};
snprintf(sub_dir, 100, "%s/%s", dir, p->d_name);
// 递归调用
myrm(sub_dir);
}
else
{
// 子是文件,就直接删除
// 拼装要删除的文件的路径
char del_path[100] = {0};
snprintf(del_path, 100, "%s/%s", dir, p->d_name);
// 调用unlink删除即可
unlink(del_path);
}
}
// 关闭文件夹
closedir(dir_p);
//删除当前空文件夹
rmdir(dir);
}
int main(int argc, char const *argv[])
{
// 通过命令传入文件夹的路径
if (argc < 2)
{
puts("缺少参数");
return -1;
}
puts(argv[1]);
// 调用stat/lstat获取文件的类型
Stat stat = {0};
lstat(argv[1], &stat);
// 判断用户输入的是文件路径还是文件夹路径
if (!S_ISDIR(stat.st_mode))
{
// 不是文件夹,就一定是文件,是文件就直接删除
int r = unlink(argv[1]);
if (r == -1)
{
perror("unlink--delete file failed");
return -1;
}
return 0;
}
// 如果是文件夹
myrm(argv[1]);
return 0;
}
多级文件夹
字符串操作 strcpy 函数:用于将源字符串复制到目标字符串数组中。这里它将命令行参数提供的路径复制到 dir_path 数组中。 strtok 函数:用于将字符串分割成一系列标记(token)。这里它根据 “/” 分隔符将路径分割成各级目录名。 snprintf 函数:用于将格式化的数据写入字符串。这里它用于将目录名与 “/” 结合,形成完整的目录路径。 strcat 函数:用于将两个字符串连接起来。这里它将逐级形成的目录路径连接起来,形成完整的要创建的目录路径。 文件系统操作 access 函数:用于检查调用进程对文件的访问权限。这里它用于检查某个目录路径是否存在(通过 F_OK 参数)。 mkdir 函数:用于创建一个新目录。这里它在确认某级目录不存在后,用于创建该目录。 错误处理 perror 函数:用于输出描述最近一次库函数调用错误的字符串。这里它在 mkdir 调用失败时被调用,以输出错误信息。 返回值检查:代码通过检查系统调用的返回值来判断操作是否成功,并在失败时返回 -1。 命令行参数 argc 和 argv:argc 表示命令行参数的数量,argv 是一个字符串数组,存储了所有的命令行参数。这里 argv[1] 存储了用户提供的目录路径。 权限设置 mode_t mode:在调用 mkdir 时,mode 参数指定了新创建目录的权限。这里使用了 0777,意味着目录对所有用户都是可读、可写和可执行的(但实际的权限可能会受到 umask 的影响)。
#include <stdio.h>
#include "header.h"
// ~/aaaa/aaa/aa/a
int mkdirMultPath(char const *dirPath, mode_t mode)
{
// 将文件夹路径的字符串转存到字符数组中
char dir_path[100] = {0};
strcpy(dir_path, dirPath);
// 定义字符串用于临时存储截取到每一层的文件夹名称(名称后有/)
char path[100] = {0};
// 存储将要创建文件夹的路径(路径中有父文件夹的层级)
char mkdir_path[100] = {0};
// 第一次截取字符串
char *subStr = NULL; // 存储截取到的文件夹的名称
if (dirPath[0] == '/')
{
mkdir_path[0] = '/';
}
subStr = strtok(dir_path, "/");
// 循环截取
while (subStr != NULL)
{
// 测试代码
// puts(subStr);
// 将截取到的字符串转存到字符数组path中
snprintf(path, 100, "%s/", subStr);
// 测试代码
// puts(path);
// 拼接成将要创建的文件夹层级
strcat(mkdir_path, path); // home/yueqian/aaaa
// 测试代码
// puts(mkdir_path);
// 判断将要创建的文件夹层级是否存在,如果存在就不创建(什么也不做),不存在才要创建
if (access(mkdir_path, F_OK) == -1)
{
// 当前文件夹不存在,就创建
if (mkdir(mkdir_path, mode) == -1)
{
perror("mkdir failed");
return -1;
}
}
// 继续截取
subStr = strtok(NULL, "/");
}
return 0;
}
int main(int argc, char const *argv[])
{
// 通过命令传入文件夹的路径
if (argc < 2)
{
puts("缺少参数");
return -1;
}
puts(argv[1]);
// 调用函数创建多级文件夹
int r = mkdirMultPath(argv[1], 0777);
if (r == -1)
{
printf("%s 多级文件创建失败\n", argv[1]);
return -1;
}
printf("%s 多级文件创建成功\n", argv[1]);
return 0;
}
标签: info ,
文件 ,
编程 ,
int ,
常见 ,
strcat ,
char ,
指令 ,
文件夹
From: https://blog.csdn.net/weixin_69851948/article/details/145075716