目录
[一、stat、fstat、lstat 获取文件属性](#一、stat、fstat、lstat 获取文件属性)
[二、chown 改变文件所有者(userID)和所属组(groupID)](#二、chown 改变文件所有者(userID)和所属组(groupID))
[三、getuid、getgid 获取用户ID和用户组ID](#三、getuid、getgid 获取用户ID和用户组ID)
[四、access 获取文件权限](#四、access 获取文件权限)
[五、chmod、fchmod 修改文件权限](#五、chmod、fchmod 修改文件权限)
[六、umask 设置权限掩码](#六、umask 设置权限掩码)
[七、link、symlink、readlink 创建硬链接、创建软链接、读取软链接、删除链接文件](#七、link、symlink、readlink 创建硬链接、创建软链接、读取软链接、删除链接文件)
[八、mkdir、rmdir 创建和删除目录](#八、mkdir、rmdir 创建和删除目录)
[九、opendir、readdir和closedir 打开、读和关闭目录](#九、opendir、readdir和closedir 打开、读和关闭目录)
[十一、chdir、fchdir 更改进程当前的工作目录](#十一、chdir、fchdir 更改进程当前的工作目录)
[十二、rename 重命名文件或移动文件](#十二、rename 重命名文件或移动文件)
Linux文件属性及目录
该文档介绍了在Linux应用编程中,文件属性的API调用和目录API的调用。以简洁的应用讲解这些API是怎么使用的,帮助您快速上手Linux应用编程。看完希望对您开发有所帮助。
一、stat、fstat、lstat 获取文件属性
cpp
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *buf);
int fstat(int fd, struct stat *buf);
//这个函数相比于上面两个,可以看链接文件本身属性
int lstat(const char *pathname, struct stat *buf);
pathname:文件路径
buf:文件属性就记录在struct stat这个结构体里面,我们传入一个这种结构体指针就行。结构体如下:
cpp
struct stat
{
dev_t st_dev; /* 文件所在设备的 ID */
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; /* 文件内容存储的块大小 */
blkcnt_t st_blocks; /* 文件内容所占块数 */
struct timespec st_atim; /* 文件最后被访问的时间 */
struct timespec st_mtim; /* 文件内容最后被修改的时间 */
struct timespec st_ctim; /* 文件状态最后被改变的时间 */
};
fd:文件描述符
返回值:成功返回0,失败返回-1。
二、chown 改变文件所有者(userID)和所属组(groupID)
cpp
#include <unistd.h>
int chown(const char *pathname, uid_t owner, gid_t group);
pathname:文件路径
owner:修改后的用户ID
group:修改后的用户组ID
(Tips:如果上面两个参数,其中有一个不想修改,使用用来的ID就行,使用stat查询就可以知道原本的ID)
返回值:成功返回0, 失败返回-1。
(Tips:使用这个函数修改文件ID,在编译运行时需要加sudo来运行,不然很有可能运行失败,原因很复杂)
三、getuid、getgid 获取用户ID和用户组ID
cpp
#include <unistd.h>
#include <sys/types.h>
uid_t getuid(void);
gid_t getgid(void);
返回值:返回用户ID或用户组ID。
四、access 获取文件权限
cpp
#include <unistd.h>
int access(const char *pathname, int mode);
pathname:文件路径
mode :有如下值:(Tips:可以使用|进行组合使用)
-
F_OK:检查文件是否存在 -
R_OK:检查文件是否有读权限。 -
W_OK:检查文件是否有写权限。 -
X_OK:检查文件是否有执行权限
返回值:成功返回0,表示用于mode参数中的权限。失败返回-1,表示mode参数中的有一个或多个不满足。
五、chmod、fchmod 修改文件权限
cpp
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
int fchmod(int fd, mode_t mode);
pathname:文件路径(Tips:如果是链接文件,这个函数改变的不是这个链接文件的权限,而是改变链接所指向文件的权限)
mode:文件权限,可以使用八进制表示,也可以使用宏,和open中的mode参数一样。
fd:文件描述符。
返回值:成功返回0, 失败返回-1。
六、umask 设置权限掩码
(Tips:实际权限 = mode & ~umask)
cpp
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);
mask:要设置的权限掩码,与open中的mode参数一样可以使用八进制或宏组合来表示。
返回值:返回旧的权限掩码
七、link、symlink、readlink 创建硬链接、创建软链接、读取软链接、删除链接文件
(Tips:可以通过ln 源文件 链接文件 来创建硬链接,可以通过ln -s 源文件 链接文件创建软链接)
cpp
#include <unistd.h>
//创建硬链接
int link(const char *oldpath, const char *newpath);
//创建软链接
int symlink(const char *target, const char *linkpath);
//读取软链接的路径信息,返回读取到的字节数,不能使用read读
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
//删除链接文件或普通文件
int unlink(const char *pathname);
oldpath:源文件路径
newpath:硬链接文件路径,注意不能指定已经存在的路径。
target:源文件路径
linkpath:软链接文件路径,不能是已经存在的路径
buf:存放路径信息
bufsiz:读取大小(字节)
pathname:要删除的文件路径
返回值:成功返回0,失败返回-1
八、mkdir、rmdir 创建和删除目录
cpp
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
//创建目录
int mkdir(const char *pathname, mode_t mode);
//删除目录
int rmdir(const char *pathname);
pathname:需要创建或删除的目录路径
mode:目录的权限设置,可以使用八进制表示或使用宏组合表示,与open中的mode参数一样。
返回值:成功返回0,失败返回-1
九、opendir、readdir和closedir 打开、读和关闭目录
cpp
#include <sys/types.h>
#include <dirent.h>
//打开目录,会返回一个DIR类型的结构体指针,叫做目录句柄DIR指针
DIR *opendir(const char *name);
//读目录,返回一个struct dirent结构体指针,遇到目录结尾返回NULL
struct dirent *readdir(DIR *dirp);
//关闭文件,成功返回0,失败返回-1
int closedir(DIR *dirp);
name:要打开的命令路径
dirp:目录句柄DIR指针
返回值struct dirent:结构体内容如下
cpp
struct dirent {
ino_t d_ino; /* inode 编号 */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported by all filesystem types */
char d_name[256]; /* 文件名 */
};
十、getcwd获取当前进程的工作目录
cpp
#include <unistd.h>
char *getcwd(char *buf, size_t size);
buf:存放当前进程工作目录的绝对路径
size:buf缓冲区的大小(字节)
返回值:成功指向buf指针,失败返回NULL
(Tips:如果buf为NULL,size为0,这个函数会自动分配一个合适的缓冲区,并将该缓冲区作为返回值返回)
十一、chdir、fchdir 更改进程当前的工作目录
cpp
#include <unistd.h>
int chdir(const char *path);
int fchdir(int fd);
path:新的工作目录路径
fd:更改为fd文件描述符所指向的目录
返回值:成功返回0,失败返回-1
十二、rename 重命名文件或移动文件
cpp
#include <stdio.h>
int rename(const char *oldpath, const char *newpath);
oldpath:原文件路径
newpath:新文件路径
返回值:成功返回0,失败返回-1
示例代码
代码需求:创建一个权限为0755的目录,并在这个目录中创建一个文件。获取这个文件的inod节点值,是否具有可读权限,获取文件的用户ID和组ID。更改文件的权限为用户可读写执行,组用户和其他用户可读和可执行。为该文件创建软链接和硬链接。获取当前进程的工作目录。
下面是我写的参考代码:
cpp
/********************************************
*项目所有的文件名:dir_file.c
*作者:SELSL
*版本:v1.0
*描述: 1、创建一个目录,目录里面再创建一个文本文件
2、先获取该文本文件的inod节点和可读权限和用户ID和用户组ID
3、修改这个文件的权限为本用户可读可写可执行,同组用户和其他用户可读可执行,
4、文件分别创建软链接和硬链接
5、获取当前工作目录
*其他:无
*论坛:无
*日志:初版 v1.0 2025/12/22 SELSL创建
********************************************/
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define myDir "./my_dir"
#define fileName "test.txt"
int main(int argc, const char *argv[])
{
//创建目录
int ret = 0;
ret = mkdir(myDir, 0755);
if(-1 == ret)
{
printf("创建目录失败\n");
exit(-1);
}
printf("目录:%s 创建成功\n", myDir);
//文件路径
char *pathName = (char *)malloc(sizeof(char) * 20);
strcat(pathName, myDir);
strcat(pathName, "/");
strcat(pathName, fileName);
//printf("文件路径生成成功\n");
//创建并打开文件
FILE *fp = NULL;
fp = fopen(pathName, "a+");
if(NULL == fp)
{
ferror(fp);
rmdir(myDir);
exit(-1);
}
//检查文件是否存在和可读
ret = access(pathName, F_OK | R_OK);
if(-1 == ret)
{
printf("文件没有读权限或文件不存在\n");
fclose(fp);
exit(-1);
}
if(0 == ret)
{
printf("文件:%s 有读权限\n", pathName);
}
//获取文件属性,并得到inode节点编号
struct stat buf;
ret = stat(pathName, &buf);
if(-1 == ret)
{
printf("文件属性获取失败\n");
fclose(fp);
exit(-1);
}
printf("成功获取文件:%s 的inode节点编号:%ld\n", pathName, buf.st_ino);
//获取用户ID和组ID
uid_t uid = 0;
gid_t gid = 0;
uid = getuid();
gid = getgid();
printf("成功获取文件:%s 的用户ID:%d 和用户组ID:%d\n", pathName, uid, gid);
//修改文件权限
ret = chmod(pathName, 0755);
if(-1 == ret)
{
printf("权限修改失败\n");
}
//为文件创建硬链接
char *hardFileName = (char *)malloc(sizeof(char) * 20);
strcat(hardFileName, myDir);
strcat(hardFileName, "/");
strcat(hardFileName, "text_hard");
ret = link(pathName, hardFileName);
if(-1 == ret)
{
printf("文件:%s 的硬链接 %s 创建失败\n", pathName, hardFileName);
}
printf("文件:%s 的硬链接 %s 创建成功\n", pathName, hardFileName);
//为文件创建软链接
char *softFileName = (char *)malloc(sizeof(char) * 20);
strcat(softFileName, myDir);
strcat(softFileName, "/");
strcat(softFileName, "text_soft");
ret = symlink(pathName, softFileName);
if(-1 == ret)
{
printf("文件:%s 的硬链接 %s 创建失败\n", pathName, hardFileName);
}
printf("文件:%s 的软链接 %s 创建成功\n", pathName, softFileName);
//获取当前进程工作目录
char *currentWorkPath = getcwd(NULL, 0);
printf("当前的工作目录为:%s\n", currentWorkPath);
fclose(fp);
return 0;
}
代码执行结果

OK,到这里就已经结束了,主要介绍了文件属性的一些API调用,和目录的一些API调用。参考了正点原子的《Linux C 应用编程参考手册》,对它进行了优化,以简洁的语言来描述了这些API的调用。希望对您的开发有所帮助。