system函数
使用 system()函数可以很方便地在我们的程序当中执行任意 shell 命令,本小节来学习下 system()函数的用法,以及介绍 system()函数的实现方法。
首先来看看 system()函数原型,如下所示:#include <stdlib.h> int system(const char *command);
这是一个库函数,使用该函数需要包含头文件<stdlib.h>。
函数参数和返回值含义如下:
command:参数 command 指向需要执行的 shell 命令,以字符串的形式提供,譬如"ls -al"、"echo HelloWorld"等。
system()函数其内部的是通过调用 fork()、execl()以及 waitpid()这三个函数来实现它的功能,首先 system()会调用 fork()创建一个子进程来运行 shell(可以把这个子进程成为 shell 进程),并通过 shell 执行参数command 所指定的命令。譬如:system("ls -la") system("echo HelloWorld")
system()的返回值如下:
⚫ 当参数 command 为 NULL,如果 shell 可用则返回一个非 0 值,若不可用则返回 0;针对一些非UNIX 系统,该系统上可能是没有 shell 的,这样就会导致 shell 不可能;如果 command 参数不为NULL,则返回值从以下的各种情况所决定。
⚫ 如果无法创建子进程或无法获取子进程的终止状态,那么 system()返回-1;
⚫ 如果子进程不能执行 shell,则 system()的返回值就好像是子进程通过调用_exit(127)终止了;
⚫ 如果所有的系统调用都成功,system()函数会返回执行 command 的 shell 进程的终止状态。
system()的主要优点在于使用上方便简单,编程时无需自己处理对 fork()、exec 函数、waitpid()以及 exit()等调用细节,system()内部会代为处理;当然这些优点通常是以牺牲效率为代价的,使用 system()运行 shell命令需要至少创建两个进程,一个进程用于运行 shell、另外一个或多个进程则用于运行参数 command 中解析出来的命令,每一个命令都会调用一次 exec 函数来执行;所以从这里可以看出,使用 system()函数其效率会大打折扣,如果我们的程序对效率或速度有所要求,那么建议大家不是直接使用 system()。一般情况下均可使用。
检查文件权限access
文件的权限检查不单单只讨论文件本身的权限,还需要涉及到文件所在目录的权限,只有同时都满足了,才能通过操作系统的权限检查,进而才可以对文件进行相关操作;所以,程序当中对文件进行相关操作之前,需要先检查执行进程的用户是否对该文件拥有相应的权限。那如何检查呢?可以使用 access 系统调用,函数原型如下:
#include <unistd.h> int access(const char *pathname, int mode);
函数参数和返回值含义如下:
pathname:需要进行权限检查的文件路径。
mode:该参数可以取以下值:
⚫ F_OK:检查文件是否存在
⚫ R_OK:检查是否拥有读权限
⚫ W_OK:检查是否拥有写权限
⚫ X_OK:检查是否拥有执行权限
除了可以单独使用之外,还可以通过按位或运算符" | "组合在一起。
返回值:检查项通过则返回 0,表示拥有相应的权限并且文件存在;否则返回-1,如果多个检查项组合在一起,只要其中任何一项不通过都会返回-1。
简单示例如下:
mkdir函数
mkdir
函数用于在文件系统中创建一个新的目录。以下是该函数的详细说明:函数原型
#include <sys/stat.h> #include <sys/types.h> int mkdir(const char *pathname, mode_t mode);
参数说明
pathname
: 要创建的目录路径名。
mode
: 设置新创建目录的访问权限。常用的权限掩码包括:
S_IRWXU
: 用户读、写和执行权限(00700)。
S_IRUSR
(S_IREAD
): 用户可读权限(00400)。
S_IWUSR
(S_IWRITE
): 用户可写权限(00200)。
S_IXUSR
(S_IEXEC
): 用户执行权限(00100)。
S_IRWXG
: 组读、写和执行权限(00070)。
S_IRGRP
: 组可读权限(00040)。
S_IWGRP
: 组可写权限(00020)。
S_IXGRP
: 组执行权限(00010)。
S_IRWXO
: 其他用户读、写和执行权限(00007)。
S_IROTH
: 其他用户可读权限(00004)。
S_IWOTH
: 其他用户可写权限(00002)。
S_IXOTH
: 其他用户执行权限(00001)。返回值
成功时返回
0
。失败时返回
-1
,并将错误记录到全局变量errno
中。示例代码
#include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <errno.h> int main() { const char *path = "/path/to/new_directory"; int res = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); // 设置权限为775 if (res == -1) { perror("Error creating directory"); return errno; } printf("Directory created successfully "); return 0; }
注意事项
权限问题:确保你有权限在指定路径下创建目录。
错误处理:使用
perror
或strerror(errno)
来获取详细的错误信息。递归创建:如果需要递归创建嵌套目录,可以使用自定义函数逐级创建每个目录。
跨平台兼容性:不同操作系统上的实现可能有所不同。例如,Windows系统使用
_mkdir
函数。
opendir函数
opendir
是一个用于打开目录的函数,通常在 C 语言中使用。该函数定义在<dirent.h>
头文件中。opendir
返回一个指向DIR
类型对象的指针,该对象可以用于遍历目录中的文件和子目录。以下是
opendir
函数的基本用法:#include <stdio.h> #include <stdlib.h> #include <dirent.h> int main() { const char *path = "."; // 当前目录 DIR *dir; struct dirent *entry; // 打开目录 dir = opendir(path); if (dir == NULL) { perror("opendir"); return EXIT_FAILURE; } // 读取目录中的每个条目 while ((entry = readdir(dir)) != NULL) { printf("%s", entry->d_name); } // 关闭目录 closedir(dir); return EXIT_SUCCESS; }
在这个示例中:
opendir
函数被用来打开指定路径的目录。如果成功,它返回一个指向DIR
结构体的指针;如果失败,则返回NULL
并设置errno
。
readdir
函数被用来读取目录中的一个条目(文件或子目录)。每次调用readdir
都会返回下一个条目,直到没有更多条目为止。
closedir
函数被用来关闭之前打开的目录。参数
const char *path
: 要打开的目录的路径。如果传递"."
, 表示当前目录;传递".."
, 表示父目录。返回值
成功时返回一个指向
DIR
结构体的指针,该结构体可以用来访问目录内容。失败时返回
NULL
,并设置errno
以指示错误原因。错误处理
常见的错误包括路径不存在、权限不足等。可以通过
perror
函数打印详细的错误信息。注意事项
确保在使用完目录后调用
closedir
来释放资源。使用
readdir
读取目录内容时,要注意处理可能的错误情况,例如目录中途被修改等。
ftw函数
ftw
(File Tree Walk)函数是一个用于遍历目录树的函数,定义在<ftw.h>
头文件中。它通过递归的方式遍历指定目录下的所有文件和子目录,并对每个文件或子目录调用用户提供的回调函数进行处理。以下是
ftw
函数的基本用法:#include <stdio.h> #include <stdlib.h> #include <ftw.h> #include <unistd.h> // 用户定义的回调函数 int my_callback(const char *filepath, const struct stat *info, int type, struct FTW *pathinfo) { printf("File: %s", filepath); return 0; // 返回0继续遍历,返回非0停止遍历 } int main() { const char *path = "."; // 当前目录 // 调用ftw函数遍历目录树 if (ftw(path, my_callback) == -1) { perror("ftw"); return EXIT_FAILURE; } return EXIT_SUCCESS; }
在这个示例中:
my_callback
是用户定义的回调函数,每次ftw
遇到一个文件或子目录时都会调用这个函数。
ftw
函数被用来遍历指定路径的目录树。如果成功,它会返回0;如果失败,则返回-1并设置errno
。参数
const char *path
: 要遍历的目录路径。如果传递"."
, 表示当前目录;传递".."
, 表示父目录。
int (*callback)(const char *filepath, const struct stat *info, int type, struct FTW *pathinfo)
: 用户提供的回调函数,每当遍历到一个文件或子目录时都会调用这个函数。回调函数参数
const char *filepath
: 当前文件或子目录的路径。
const struct stat *info
: 指向stat
结构体的指针,包含文件的状态信息。
int type
: 文件类型,可能是以下几种:
FTW_D
: 目录。
FTW_DNR
: 不可读目录。
FTW_DP
: 符号链接指向的目录。
FTW_F
: 普通文件。
FTW_NS
: 无法访问的文件。
FTW_SL
: 符号链接。
FTW_SLN
: 不可读的符号链接。
struct FTW *pathinfo
: 指向FTW
结构体的指针,包含了额外的信息。返回值
成功时返回0。
失败时返回-1,并设置
errno
以指示错误原因。注意事项
确保回调函数正确处理各种文件类型和错误情况。
ftw
不会自动处理符号链接,对于符号链接需要特别小心,以免陷入无限循环。补充:
ftw(dir, cb ,1000)
ftw
函数的第三个参数是nopenfd
,它指定了在遍历目录树时可以同时打开的文件描述符的最大数量。这个参数用于限制并发打开的文件数,以避免资源耗尽的问题。
unlink函数
unlink函数是一个用于删除文件的系统调用。以下是关于unlink函数的具体介绍:
函数原型
头文件:#include <unistd.h>。
函数原型:int unlink(const char *pathname)。
参数说明:pathname是要删除的文件路径,可以是相对路径或绝对路径。
工作原理
连接数检查:unlink函数会先检查文件系统中此文件的连接数是否为1,如果不是1说明此文件还有其他链接对象,因此只对此文件的连接数进行减1操作。
实际删除:若连接数为1,并且在此时没有任何进程打开该文件,此内容才会真正地被删除掉。在有进程打开此文件的情况下,则暂时不会删除,直到所有打开该文件的进程都结束时文件就会被删除。
返回值
成功:成功执行时,返回0。
失败:失败返回-1,并设置相应的错误码。
使用场景
文件管理:unlink函数常用于日常文件管理中的文件删除操作。
临时文件处理:在程序运行过程中可能会产生一些临时文件,使用unlink函数可以方便地将这些临时文件删除。
数据安全:在某些情况下,为了确保数据安全,需要频繁删除敏感信息的文件。
总的来说,unlink函数是Linux系统中一个非常重要的系统调用,它提供了一种从文件系统中删除文件的方法。在使用unlink函数时,需要注意其对文件连接数的影响以及可能的错误情况。