Linux(四)函数获知文件、目录的属性、权限
ubuntu下
用函数判断文件的权限、类型,需要用到上图所示的宏常量,这些宏定义在C语言库里,我们可以直接使用这些宏。
一、获取文件属性
1.1 stat
函数功能:通过文件名(带路径)获取文件属性(节点号、文件类型、链接数、属主 ID、文件大小等 )
函数原型:int stat(const char *path,struct stat *buf)
头文件:#include<sys/types.h>、#include<sys/stat.h>、#include<unistd.h>
参数:const char *path: 带路径的文件名,
struct stat *buf :文件属性结构体变量的地址
struct stat {
dev_t st_dev; /*如果是设备,返回设备表述符,否则为 0*/
ino_t st_ino; /* i 节点号 */
mode_t
mode 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; /* 系统每次按块Io操作时块的大小(一般是512或1024)*/
blkcnt_t st_blocks; /*块的索引号 */
time_t st_atime; /* 最后访问时间,如read*/
time_t st_mtime; /* 最后修改时间*/
time_t st_ctime; /*显示的是文件的权限、拥有者、所属的组、链接数发生改变时的时间。当然当内容改变时也会随之改变 */
};
返回值:成功返回0,失败返回-1
示例代码:通过stat函数 获取文件 属性 模仿ls -ail 的功能
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
struct stat buf;
int main(int argv,char* argc[])
{
char fileProperty[11]={'-','-','-','-','-','-','-','-','-','-','\0'}; //存储文件类型(第1个字节)和读写权限(后9个字节)
unsigned long nlink; //链接数
stat(argc[1],&buf);
/*获取文件的类型*/
switch ((buf.st_mode&S_IFMT))
{
case S_IFSOCK: fileProperty[0] = 's'; break;//套节字文件(s)
case S_IFREG: fileProperty[0] = '-'; break;//普通文件(-)
case S_IFLNK: fileProperty[0] = 'l'; break;//链接文件(l)
case S_IFCHR: fileProperty[0] = 'c'; break;//字符设备文件(c)
case S_IFIFO: fileProperty[0] = 'p'; break;//管道文件(p)
case S_IFDIR: fileProperty[0] = 'd'; break;//目录文件(d)
case S_IFBLK: fileProperty[0] = 'b'; break;//块设备文件(b)
default:
break;
}
/*获取文件的读写权限*/
char i = 1;
unsigned int off = 256;
for (char j = 0; j < 10; j++)
{
switch (buf.st_mode&off>>j)
{
case S_IRUSR: fileProperty[1] = 'r'; break;//文件所属用户
case S_IWUSR: fileProperty[2] = 'w'; break;//文件所属用户
case S_IXUSR: fileProperty[3] = 'x'; break;//文件所属用户
case S_IRGRP: fileProperty[4] = 'r'; break;//组用户
case S_IWGRP: fileProperty[5] = 'w'; break;//组用户
case S_IXGRP: fileProperty[4] = 'x'; break;//组用户
case S_IROTH: fileProperty[7] = 'r'; break;//其他用户
case S_IWOTH: fileProperty[8] = 'w'; break;//其他用户
case S_IXOTH: fileProperty[9] = 'x'; break;//其他用户
default:
break;
}
}
/*获取链接数*/
nlink = buf.st_nlink;
/*通过文件所属的用户ID,获取文件所属用户名*/
//获取到 user_id, group_id, 调用 getpwuid/getgrgid 即可
struct passwd * user = NULL;
struct group * group = NULL;
user = getpwuid(buf.st_uid);
group = getgrgid(buf.st_gid);
/*获取文件大小*/
unsigned long fileSize;
fileSize = buf.st_size;
/*获取最近修改时间*/
struct tm *loTim = NULL;
loTim = localtime(&buf.st_ctime);
/*******输出文件属性信息********/
printf("%lu %s %lu %s %s %lu %d年%02d月%02d日 %02d:%02d:%02d %s\n",buf.st_ino,fileProperty,nlink,user->pw_name,group->gr_name,fileSize,loTim->tm_year + 1900,loTim->tm_mon+1,loTim->tm_mday,loTim->tm_hour,loTim->tm_min,loTim->tm_sec,argc[1]);
return 0;
}
1.2 fstat
函数功能:通过文件描述符获取文件属性(节点号、文件类型、链接数、属主 ID、文件大小等 ),需要打开文件获取文件描述符,用法与stat类似
函数原型:int fstat(int fds,struct stat *buf);
头文件:#include<sys/types.h>、#include<sys/stat.h>、#include<unistd.h>
参数:int fds : 文件描述符
struct stat *buf : 文件属性结构体变量的地址
返回值:成功返回0,失败返回-1
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include<time.h>
#include <fcntl.h>
struct stat buf;
int main(int argv,char* argc[])
{
char fileProperty[11]={'-','-','-','-','-','-','-','-','-','-','\0'}; //存储文件类型(第1个字节)和读写权限(后9个字节)
unsigned long nlink; //链接数
int fd;
fd = open(argc[1],O_RDONLY);
// stat(argc[1],&buf);
fstat(fd,&buf);
/*获取文件的类型*/
switch ((buf.st_mode&S_IFMT))
{
case S_IFSOCK: fileProperty[0] = 's'; break;//套节字文件(s)
case S_IFREG: fileProperty[0] = '-'; break;//普通文件(-)
case S_IFLNK: fileProperty[0] = 'l'; break;//链接文件(l)
case S_IFCHR: fileProperty[0] = 'c'; break;//字符设备文件(c)
case S_IFIFO: fileProperty[0] = 'p'; break;//管道文件(p)
case S_IFDIR: fileProperty[0] = 'd'; break;//目录文件(d)
case S_IFBLK: fileProperty[0] = 'b'; break;//块设备文件(b)
default:
break;
}
/*获取文件的读写权限*/
char i = 1;
unsigned int off = 256;
for (char j = 0; j < 10; j++)
{
switch (buf.st_mode&off>>j)
{
case S_IRUSR: fileProperty[1] = 'r'; break;
case S_IWUSR: fileProperty[2] = 'w'; break;
case S_IXUSR: fileProperty[3] = 'x'; break;
case S_IRGRP: fileProperty[4] = 'r'; break;
case S_IWGRP: fileProperty[5] = 'w'; break;
case S_IXGRP: fileProperty[4] = 'x'; break;
case S_IROTH: fileProperty[7] = 'r'; break;
case S_IWOTH: fileProperty[8] = 'w'; break;
case S_IXOTH: fileProperty[9] = 'x'; break;
default:
break;
}
}
/*获取链接数*/
nlink = buf.st_nlink;
/*通过文件所属的用户ID,获取文件所属用户名*/
//获取到 user_id, group_id, 调用 getpwuid/getgrgid 即可
struct passwd * user = NULL;
struct group * group = NULL;
user = getpwuid(buf.st_uid);
group = getgrgid(buf.st_gid);
/*获取文件大小*/
unsigned long fileSize;
fileSize = buf.st_size;
/*获取最近修改时间*/
// char* localTime = ctime(buf.st_ctime);
/*******输出文件属性信息********/
struct tm *loTim = NULL;
loTim = localtime(&buf.st_ctime);
printf("%lu %s %lu %s %s %lu %d年%02d月%02d日 %02d:%02d:%02d %s\n",buf.st_ino,fileProperty,nlink,user->pw_name,group->gr_name,fileSize,loTim->tm_year + 1900,loTim->tm_mon+1,loTim->tm_mday,loTim->tm_hour,loTim->tm_min,loTim->tm_sec,argc[1]);
return 0;
}
1.3 lstat
函数功能:获取的是链接文件的文件属性(节点号、文件类型、链接数、属主 ID、文件大小等 ),需要打开文件获取文件描述符,用法与stat类似
函数原型:int lstat(const char *path,struct stat *buf);
头文件:#include<sys/types.h>、#include<sys/stat.h>、#include<unistd.h>
参数:const char *path : 文件名(含路径)
struct stat *buf : 文件属性结构体变量的地址
返回值:成功返回0,失败返回-1
示例:
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include<time.h>
#include <fcntl.h>
struct stat buf;
int main(int argv,char* argc[])
{
char fileProperty[11]={'-','-','-','-','-','-','-','-','-','-','\0'}; //存储文件类型(第1个字节)和读写权限(后9个字节)
unsigned long nlink; //链接数
int fd;
// fd = open(argc[1],O_RDONLY);
// stat(argc[1],&buf);
// fstat(fd,&buf);
lstat(argc[1],&buf);
/*获取文件的类型*/
switch ((buf.st_mode&S_IFMT))
{
case S_IFSOCK: fileProperty[0] = 's'; break;//套节字文件(s)
case S_IFREG: fileProperty[0] = '-'; break;//普通文件(-)
case S_IFLNK: fileProperty[0] = 'l'; break;//链接文件(l)
case S_IFCHR: fileProperty[0] = 'c'; break;//字符设备文件(c)
case S_IFIFO: fileProperty[0] = 'p'; break;//管道文件(p)
case S_IFDIR: fileProperty[0] = 'd'; break;//目录文件(d)
case S_IFBLK: fileProperty[0] = 'b'; break;//块设备文件(b)
default:
break;
}
/*获取文件的读写权限*/
char i = 1;
unsigned int off = 256;
for (char j = 0; j < 10; j++)
{
switch (buf.st_mode&off>>j)
{
case S_IRUSR: fileProperty[1] = 'r'; break;
case S_IWUSR: fileProperty[2] = 'w'; break;
case S_IXUSR: fileProperty[3] = 'x'; break;
case S_IRGRP: fileProperty[4] = 'r'; break;
case S_IWGRP: fileProperty[5] = 'w'; break;
case S_IXGRP: fileProperty[4] = 'x'; break;
case S_IROTH: fileProperty[7] = 'r'; break;
case S_IWOTH: fileProperty[8] = 'w'; break;
case S_IXOTH: fileProperty[9] = 'x'; break;
default:
break;
}
}
/*获取链接数*/
nlink = buf.st_nlink;
/*通过文件所属的用户ID,获取文件所属用户名*/
//获取到 user_id, group_id, 调用 getpwuid/getgrgid 即可
struct passwd * user = NULL;
struct group * group = NULL;
user = getpwuid(buf.st_uid);
group = getgrgid(buf.st_gid);
/*获取文件大小*/
unsigned long fileSize;
fileSize = buf.st_size;
/*获取最近修改时间*/
// char* localTime = ctime(buf.st_ctime);
/*******输出文件属性信息********/
struct tm *loTim = NULL;
loTim = localtime(&buf.st_ctime);
printf("%lu %s %lu %s %s %lu %d年%02d月%02d日 %02d:%02d:%02d %s\n",buf.st_ino,fileProperty,nlink,user->pw_name,group->gr_name,fileSize,loTim->tm_year + 1900,loTim->tm_mon+1,loTim->tm_mday,loTim->tm_hour,loTim->tm_min,loTim->tm_sec,argc[1]);
return 0;
}
结果:
-
stat 和 fstat的差别:stat通过文件名获取文件属性(不需要打开文件),fstat通过文件描述符获取属性(需要打开文件)
-
stat 和 lstat的区别:stat获取文件的属性的时候获取的是链接文件所指向的文件的属性,lstat获取的是链接文件的属性
通过shell指令获取文件属性
ls -ail
ls 命令实际上就是调用stat等系统调用的函数读取文件属性并显示出来
1.4 access
函数功能:检测当前用户(运行这个程序的用户)对该文件是否有某权限
函数原型:int access(const char *pathname, int mode);
头文件:#include<unistd.h>
参数:const char *pathname : 文件名(含路径)
int mode:权限类型,可组合使用
R_OK:测试读权限
W_OK:测试写权限
X_OK:测试执行权限
F_OK:测试文件是否存在 : 文件属性结构体变量的地址
返回值:成功返回0,失败返回-1
示例:
#include<stdio.h>
#include <unistd.h>
int main(int argv,char* argc[])
{
int status;
status = access(argc[1],R_OK);
if (status < 0)
{
printf("无读权限\n");
}
else
{
printf("有读权限\n");
}
return 0;
}
结果:
二、目录操作
2.1 mkdir
函数功能:创建目录文件(不能一次创建多级目录)
函数原型:int mkdir(const char *pathname, mode_t mode);
头文件:#include<sys/types.h>、#include<sys/stat.h>
参数:const char *pathname: 文件名(含路径)
mode: 文件权限用数字或宏表示
返回值:成功返回0,失败返回-1
示例:
#include<stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#define U8 unsigned char
int main(void)
{
U8 status;
status = mkdir("dir1",0664);
if (status < 0)
{
perror("mkdir");
}
printf("操作结束\n");
return 0;
}
结果:
2.2 rmdir
函数功能:删除目录文件(只能删除空文件)
函数原型:int rmdir(const char *pathname);
头文件:#include<sys/types.h>、#include<sys/stat.h>
参数:const char *pathname: 要删除的目录路径
返回值:成功返回0,失败返回-1
#include<stdio.h>
#include<unistd.h>
#define U8 unsigned char
int main(void)
{
U8 status;
status = rmdir("dir1");
if (status < 0)
{
perror("rmdir");
}
printf("操作结束\n");
return 0;
}
2.3 getcwd(类似于shell指令里的pwd)
函数功能:获取当前所在路径
函数原型:char *getcwd(char *buf, size_t size);
头文件:#include<unistd.h>
参数: buf:存放路径的缓存区
size:缓存区的大小 能保存的最大值为255 路径长度最多能是255
返回值:成功返回路径,失败返回NULL
示例:
#include<stdio.h>
#include<unistd.h>
#define U8 unsigned char
int main(void)
{
U8 status;
char buf[255];
char *pwd = NULL;
pwd = getcwd(buf,255);
if (NULL == pwd)
{
perror("getcwd");
}
printf("当前路径: %s\n",buf);
return 0;
}
结果:
2.4 get_current_dir_name
函数功能:获取当前所在路径 (注意:使用时要在第一行加上#define _GNU_SOURCE)
函数原型:char *get_current_dir_name(void);
头文件:#include<unistd.h>
参数: 无
返回值:成功返回路径,失败返回NULL
#define _GNU_SOURCE
#include<stdio.h>
#include<unistd.h>
#define U8 unsigned char
int main(void)
{
U8 status;
char *pwd = NULL;
pwd = get_current_dir_name();
if (NULL == pwd)
{
perror("getcwd");
}
printf("当前路径: %s\n",pwd);
return 0;
}
2.5 chmod
功能:更改文件权限
函数原型:int chmod(const char *path, mode_t mode);
所属头文件: #include <sys/types.h>
#include <sys/stat.h>
参数:path:文件路径
mode:权限
返回值:成功返回0,失败返回-1
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
int main()
{
char status;
status = chmod("test.txt",0666);
if (status < 0)
{
perror("chdir");
}
return 0;
}
2.6 opendir (和文件函数open、fopen用法类似)
功能:打开目录
函数原型:DIR *opendir(const char *name);
所属头文件:
\#include <sys/types.h>
\#include <dirent.h>
参数:目录的路径
返回值:成功返回指向当前目录的指针,错误返回NULL
/* 我们不用关心DIR指针的内部实现,就像我们不用关心FILE指针一样 */
typedef struct __dirstream DIR;
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. */
};
2.7 closedir (和 文件关闭函数close、fclose类似)
函数功能:关闭目录
函数头文件:
\#include <sys/types.h>
\#include <dirent.h>
函数原型:int closedir(DIR *dir);
函数参数: DIR *dir:目录流指针
函数返回值:成功返回0 ,失败返回-1
2.8 readdir (和 文件读函数 read、fread类似)
函数功能: 读取目录文件,目录中的文件信息(文件名、扩展名等等)
函数头文件:
\#include <sys/types.h>
\#include <dirent.h>
函数原型: struct dirent *readdir(DIR *dirp);
函数参数: DIR *dirp:目录流指针
函数返回值:成功返回:指向存放目录相关信息的结构体指针 , 失败:返回NULL
struct dirent结构体
// 存储目录中的文件信息(文件名、扩展名等等)
#include<dirent.h>
struct dirent
{
long d_ino; /* inode number 索引节点号 */
off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
unsigned short d_reclen; /* length of this d_name 文件名长 */
unsigned char d_type; /* the type of d_name 文件类型 */
char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */
}
2.6、2.7、2.8 示例代码:
#include<stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main()
{
char status;
DIR* mydir;
struct dirent * mydirent;
mydir = opendir("test");
if (NULL == mydir)
{
perror("opendir");
}
// mydirent = readdir(mydir);
while ((mydirent = readdir(mydir)) != NULL)
{
printf("索引节点号: %lu\n",mydirent->d_ino);
printf("在目路文件中的偏移: %ld\n",mydirent->d_off);
printf("文件名长度: %d\n",mydirent->d_reclen);
printf("文件类型: %d\n",mydirent->d_type);
printf("文件名: %s\n",mydirent->d_name);
printf("**************************************\n");
}
status = closedir(mydir);
if (status < 0)
{
perror("closedir");
}
return 0;
}
结果:
2.9.0 rewinddir
功能:重新定位到目录文件的头部 ( 相当于文件里的读写位置 )
函数原型:void rewinddir(DIR *dir);
所属头文件:
\#include <sys/types.h>
\#include <dirent.h>
参数:打开目录后返回的文件指针
返回值:无
2.9.1 seekdir
功能:设置参数dir 目录流目前的读取位置, 在调用readdir()时便从此新位置开始读取. 参数offset 代表距离目录文件开头的偏移量。
函数原型:void seekdir(DIR *dir,off_t offset);
所属头文件
\#include <sys/types.h>
\#include <dirent.h>
参数: DIR *dir: 打开目录后返回的文件指针
offset :代表距离目录文件开头的偏移量
返回值:无
2.9.2 telldir
功能:取得目录流的读取位置
函数原型:off_t telldir(DIR *dir);
所属头文件:
#include <sys/types.h>
#include <dirent.h>
参数:DIR *dir :打开目录后返回的文件指针
返回值:成功返回距离目录文件开头的偏移量返回值返回下个读取位置, 有错误发生时返回-1
2.9.0、2.9.1、2.9.2 示例代码:
#include<stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main()
{
char status;
DIR* mydir = NULL;
struct dirent * mydirent = NULL;
mydir = opendir("./test");
if (NULL == mydir)
{
perror("opendir");
}
// mydirent = readdir(mydir);
while ((mydirent = readdir(mydir)) != NULL)
{
printf("索引节点号: %lu\n",mydirent->d_ino);
printf("在目路文件中的偏移: %ld\n",mydirent->d_off);
printf("文件名长度: %d\n",mydirent->d_reclen);
printf("文件类型: %d\n",mydirent->d_type);
printf("文件名: %s\n",mydirent->d_name);
printf("**************************************\n");
}
rewinddir(mydir);
printf("使用rewinddir之后,目录指针指向目录文件开头\n");
while ((mydirent = readdir(mydir)) != NULL)
{
printf("索引节点号: %lu\n",mydirent->d_ino);
printf("在目路文件中的偏移: %ld\n",mydirent->d_off);
printf("文件名长度: %d\n",mydirent->d_reclen);
printf("文件类型: %d\n",mydirent->d_type);
printf("文件名: %s\n",mydirent->d_name);
printf("*************************\n");
}
status = closedir(mydir);
if (status < 0)
{
perror("closedir");
}
return 0;
}
结果: