赞
踩
在linux的shell解释器中,输入这样的命令stat + 文件名即可获取文件的属性。如:
我们可以通过以下函数获取上面的值
#include<unistd.h> #include<sys/stat.h> #include<sys/types.h> int fstat(int fildes, struct stat *buf); int lstat(const char *pathname, struct stat *buf); int stat(const char *pathname, struct stat *buf); int fstat64(int fildes, struct stat64 *buf); int lstat64(const char *pathname, struct stat64 *buf); int stat64(const char *pathname, struct stat64 *buf); struct stat { dev_t st_dev; 文件的设备编号 ino_t st_ino; 节点 mode_t st_mode; 文件的类型和权限 nlink_t st_nlink; 连到该文件的硬链接数目,刚建立的文件值为1 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; 块数 time_t st_atime; 最后一次访问时间 time_t st_mtime; 最后一次修改时间 time_t st_ctime; 最后一次改变时间(指属性) }; 返回值: 是成功是返回0,否则返回-1,并设置对应的errno 常见的可能出现的errno有: EACCES:目标文件所在的目录或某个上级目录没有查找权限 EBADF:指定的文件描述符无效. EFAULT:无效的文件地址 ELOOP:可能遇到了循环引用的软链接文件 ENAMETOOLONG:文件路径名太长. ENOENT:目录或文件不存在 ENOMEM:内核内存耗尽 ENOTDIR:指定的文件路径上,某个部分不是目录 EOVERFLOW:引用的文件太大了,或者使用的索引节点太多了,或者占用的存储块太多了。
系统调用 stat()和 lstat()无需对其所操作的文件本身拥有任何权限,但针对指pathname 的父目录要有执行(搜索)权限。而只要供之以有效的文件描述符,fstat()系统调用总是成功
磁盘上的文件由很多属性,比如文件大小,文件属组等。如果要得到文件属性,进程可以定义一个结构struct stat,然后调用stat,告诉内核将这个文件属性复制到这个结构中:
int main()
{
struct stat st;//定义结构体变量,保存所获取的文件属性
int res = stat("valgrind.sh", &st);
if(res == -1)//获取文件属性失败,errno设置为合适的值
{
perror("stat fail");
}{
printf("文件大小:%ld 块数: %ld 文件I/O缓冲区块大小: %ld\n",st.st_size, st.st_blocks, st.st_blksize);
}
}
利用以上两者,可在所有文件系统中唯一标识某个文件。
st_uid 和 st_gid 字段分别标识文件的属主(用户 ID)和属组(组 ID)。
每个文件都有文件所有者,Unix通过uid和gid来表示文件所有者和文件所属组
可以通过chown来修改文件的所有者和组
st_mode 字段内含有位掩码,起标识文件类型和指定文件权限的双重作用。
字段的编码
把多种信息编码到一个整数的不同字段中是一种常用的技术,比如:
613-495-4209 | 电话号码(区号-局号-线号) |
127.102.33.100 | IP地址 |
如何读取被编码的值
怎么直到212-222-4444所对应的区号是212?
这种把不需要的地方置于0的技术就叫做掩码
使用掩码来解码得到的文件类型
文件类型的模式字段的第一个字节的前4位,可以通过掩码来讲其他部分置于0,从而得到类型的值
在< sys/stat.h>下有如下定义:
#if defined __USE_BSD || defined __USE_MISC || defined __USE_XOPEN # define S_IFMT __S_IFMT # define S_IFDIR __S_IFDIR # define S_IFCHR __S_IFCHR # define S_IFBLK __S_IFBLK # define S_IFREG __S_IFREG # ifdef __S_IFIFO # define S_IFIFO __S_IFIFO # endif # ifdef __S_IFLNK # define S_IFLNK __S_IFLNK # endif #define __S_IFMT 0170000 /* These bits determine file type. */ /* File types. */ #define __S_IFDIR 0040000 /* Directory. */ #define __S_IFCHR 0020000 /* Character device. */ #define __S_IFBLK 0060000 /* Block device. */ #define __S_IFREG 0100000 /* Regular file. */ #define __S_IFIFO 0010000 /* FIFO. */ #define __S_IFLNK 0120000 /* Symbolic link. */ #define __S_IFSOCK 0140000 /* Socket. */
举个例子,掩码__S_IFMT 的值为0170000 ,可以用来过滤出前四位表示的文件类型。__S_IFREG 就表示普通文件,也就是说:
if((statbuf.st_mode & S_IFMT) == S_IFREG){
printf("regular file\n");
}
与常量 S_IFMT 相与(&),可从该字段中析取文件类型
更简单的方法使用< sys/stat.h> 中的宏来代替上述代码:
#define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))
#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
#define S_ISCHR(mode) __S_ISTYPE((mode), __S_IFCHR)
#define S_ISBLK(mode) __S_ISTYPE((mode), __S_IFBLK)
#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)
#ifdef __S_IFIFO
# define S_ISFIFO(mode) __S_ISTYPE((mode), __S_IFIFO)
#endif
#ifdef __S_IFLNK
# define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
#endif
也就是说:
if(S_ISREG(statbuf.st_mode)){
printf("regular file\n");
}
下表所列为全套文件类型宏(定义于< sys/stat.h>)。这些宏均由 SUSv3 定义,并为 Linux所支持。
常 量 | 测 试 宏 | 文 件 类 型 |
---|---|---|
S_IFREG | S_ISREG() | 常规文件 |
S_IFDIR | S_ISDIR() | 目录 |
S_IFCHR | S_ISCHR() | 字符设备 |
S_IFBLK | S_ISBLK() | 块设备 |
S_IFIFO | S_ISFIFO() | FIFO 或管道 |
S_IFSOCK | S_ISSOCK() | 套接字 |
S_IFLNK | S_ISLNK() | 符号链接 |
因为调用 stat()时会循符号链接而直抵实际文件,所以只有在调用 lstat()时才有可能返回类型 S_IFLNK。
文件类型是在创建文件的时候建立的,比如系统调用creat可以创建一个普通文件,其他类型的文件比如目录、设备等,可以使用不同的函数创建
文件一经创建,就无法修改
st_size
st_blocks
st_blksize
/** * 根据文件名取得该文件的大小 * @param filename {const char*} 文件名 * @return {acl_int64} >= 0: ok; -1: error */ acl_int64 acl_file::acl_file_size(const char *filename){ struct stat sbuf; if (stat(filename, &sbuf) == -1) { return -1; } return sbuf.st_size; } /** * 根据文件句柄取得该文件的大小 * @param fp {ACL_VSTREAM*} 对应的文件流句柄, 可以为空 * @param arg {void*} 用户传递的参数, 以回调方式使用时此参数有效 * @return {acl_int64} >= 0: ok; -1: error */ acl_int64 acl_file::acl_file_fsize(ACL_VSTREAM *fp, void *arg){ struct stat sbuf; if (fstat(file_handle_, &sbuf) == -1) { return -1; } return sbuf.st_size; }
st_atime、st_mtime 和 st_ctime 字段,分别记录了对文件的上次访问时间、上次修改时间,以及文件状态发生改变的上次时间。这 3 个字段的类型均属 time_t,是标准的 UNIX 时间格式,记录了自 Epoch 以来的秒数
#include <time.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> int main() { struct stat st;//定义结构体变量,保存所获取的文件属性 int res = stat("/home/oceanstar/CLionProjects/c/build/valgrind.sh", &st); if(res == -1)//获取文件属性失败,errno设置为合适的值 { perror("stat fail"); return (1); } printf("文件大小:%ld 块数: %ld 文件I/O缓冲区块大小: %ld\n",st.st_size, st.st_blocks, st.st_blksize); printf("设备编号:%lu Inode:%lu 硬链接:%lu\n ",st.st_dev, st.st_ino, st.st_nlink); printf("权限:%u , 用户ID:%d 组ID:%d \n ",st.st_mode, st.st_uid, st.st_gid); switch (st.st_mode & S_IFMT) { case S_IFBLK: printf("block device\n"); break; case S_IFCHR: printf("character device\n"); break; case S_IFDIR: printf("directory\n"); break; case S_IFIFO: printf("FIFO/pipe\n"); break; case S_IFLNK: printf("symlink\n"); break; case S_IFREG: printf("regular file\n"); break; case S_IFSOCK: printf("socket\n"); break; default: printf("unknown?\n"); break; } printf("Last status change: %s", ctime(&st.st_ctime)); printf("Last file access: %s", ctime(&st.st_atime)); printf("Last file modification: %s", ctime(&st.st_mtime)); return 0; }
#include <sys/sysmacros.h> #if defined(_AIX) #define _BSD #endif #if defined(__sgi) || defined(__sun) /* Some systems need this */ #include <sys/mkdev.h> /* To get major() and minor() */ #endif #if defined(__hpux) /* Other systems need this */ #include <sys/mknod.h> #endif #include <sys/stat.h> #include <time.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/stat.h> #include <stdio.h> #include <sys/types.h> #define FP_SPECIAL 1 /* Include set-user-ID, set-group-ID, and sticky bit information in returned string */ #define STR_SIZE sizeof("rwxrwxrwx") char * /* Return ls(1)-style string for file permissions mask */ filePermStr(mode_t perm, int flags) { static char str[STR_SIZE]; /* If FP_SPECIAL was specified, we emulate the trickery of ls(1) in returning set-user-ID, set-group-ID, and sticky bit information in the user/group/other execute fields. This is made more complex by the fact that the case of the character displayed for this bits depends on whether the corresponding execute bit is on or off. */ snprintf(str, STR_SIZE, "%c%c%c%c%c%c%c%c%c", (perm & S_IRUSR) ? 'r' : '-', (perm & S_IWUSR) ? 'w' : '-', (perm & S_IXUSR) ? (((perm & S_ISUID) && (flags & FP_SPECIAL)) ? 's' : 'x') : (((perm & S_ISUID) && (flags & FP_SPECIAL)) ? 'S' : '-'), (perm & S_IRGRP) ? 'r' : '-', (perm & S_IWGRP) ? 'w' : '-', (perm & S_IXGRP) ? (((perm & S_ISGID) && (flags & FP_SPECIAL)) ? 's' : 'x') : (((perm & S_ISGID) && (flags & FP_SPECIAL)) ? 'S' : '-'), (perm & S_IROTH) ? 'r' : '-', (perm & S_IWOTH) ? 'w' : '-', (perm & S_IXOTH) ? (((perm & S_ISVTX) && (flags & FP_SPECIAL)) ? 't' : 'x') : (((perm & S_ISVTX) && (flags & FP_SPECIAL)) ? 'T' : '-')); return str; } static void displayStatInfo(const struct stat *sb) { printf("File type: "); switch (sb->st_mode & S_IFMT) { case S_IFREG: printf("regular file\n"); break; case S_IFDIR: printf("directory\n"); break; case S_IFCHR: printf("character device\n"); break; case S_IFBLK: printf("block device\n"); break; case S_IFLNK: printf("symbolic (soft) link\n"); break; case S_IFIFO: printf("FIFO or pipe\n"); break; case S_IFSOCK: printf("socket\n"); break; default: printf("unknown file type?\n"); break; } printf("Device containing i-node: major=%ld minor=%ld\n", (long) major(sb->st_dev), (long) minor(sb->st_dev)); printf("I-node number: %ld\n", (long) sb->st_ino); printf("Mode: %lo (%s)\n", (unsigned long) sb->st_mode, filePermStr(sb->st_mode, 0)); if (sb->st_mode & (S_ISUID | S_ISGID | S_ISVTX)) printf(" special bits set: %s%s%s\n", (sb->st_mode & S_ISUID) ? "set-UID " : "", (sb->st_mode & S_ISGID) ? "set-GID " : "", (sb->st_mode & S_ISVTX) ? "sticky " : ""); printf("Number of (hard) links: %ld\n", (long) sb->st_nlink); printf("Ownership: UID=%ld GID=%ld\n", (long) sb->st_uid, (long) sb->st_gid); if (S_ISCHR(sb->st_mode) || S_ISBLK(sb->st_mode)) printf("Device number (st_rdev): major=%ld; minor=%ld\n", (long) major(sb->st_rdev), (long) minor(sb->st_rdev)); printf("File size: %lld bytes\n", (long long) sb->st_size); printf("Optimal I/O block size: %ld bytes\n", (long) sb->st_blksize); printf("512B blocks allocated: %lld\n", (long long) sb->st_blocks); printf("Last file access: %s", ctime(&sb->st_atime)); printf("Last file modification: %s", ctime(&sb->st_mtime)); printf("Last status change: %s", ctime(&sb->st_ctime)); } int main(int argc, char *argv[]) { struct stat sb; bool statLink; /* True if "-l" specified (i.e., use lstat) */ int fname; /* Location of filename argument in argv[] */ statLink = (argc > 1) && strcmp(argv[1], "-l") == 0; /* Simple parsing for "-l" */ fname = statLink ? 2 : 1; if (fname >= argc || (argc > 1 && strcmp(argv[1], "--help") == 0)){ printf("%s [-l] file\n" " -l = use lstat() instead of stat()\n", argv[0]); exit(EXIT_FAILURE); } if (statLink) { if (lstat(argv[fname], &sb) == -1) { perror("lstat"); exit(EXIT_FAILURE); } } else { if (stat(argv[fname], &sb) == -1){ perror("stat"); exit(EXIT_FAILURE); } } displayStatInfo(&sb); exit(EXIT_SUCCESS); }
第二个例子:
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> int main (int argc, char**argv) { struct stat s; char *type, *readok; stat(argv[1], &s); if (S_ISREG(s.st_mode)){ type= "regular"; }else if(S_ISDIR(s.st_mode)){ type= "directory"; }else{ type= "other"; } if ((s.st_mode & S_IRUSR)){ readok = "yes"; }else{ readok = "no"; } printf("type: %s, read: %s\n", type, readok); return(0); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。