stat,fstate,lstat函数
- #include <sys/stat.h>
- int stat (const char *restrict pathname,struct stat* restrict buf)
- int fstat(int filedes,struct stat *buf);
- int lstat(const char *restrict pathname,struct stat *restrict buf);
stat, fstat and lstat是用来检查文件属性的。他们将文件属性信息通过a struct stat object 返回。
int stat (const char *filename, struct stat *buf) [Function]
The stat function returns information about the attributes of the file named by
filename in the structure pointed to by buf.
If filename is the name of a symbolic link, the attributes you get describe the file
that the link points to. If the link points to a nonexistent file name, then stat fails
reporting a nonexistent file.
The return value is 0 if the operation is successful, or -1 on failure. In addition to the
usual file name errors (see Section 11.2.3 [File Name Errors], page 224, the following
errno error conditions are defined for this function:
ENOENT The file named by filename doesn’t exist.
When the sources are compiled with _FILE_OFFSET_BITS == 64 this function is in fact
stat64 since the LFS interface transparently replaces the normal implementation.
int fstat (int filedes, struct stat *buf) [Function]
The fstat function is like stat, except that it takes an open file descriptor as an
argument instead of a file name. See Chapter 13 [Low-Level Input/Output], page 296.
Like stat, fstat returns 0 on success and -1 on failure. The following errno error
conditions are defined for fstat:
EBADF The filedes argument is not a valid file descriptor.
When the sources are compiled with _FILE_OFFSET_BITS == 64 this function is in fact
fstat64 since the LFS interface transparently replaces the normal implementation.
int lstat (const char *filename, struct stat *buf) [Function]
The lstat function is like stat, except that it does not follow symbolic links. If
filename is the name of a symbolic link, lstat returns information about the link
itself; otherwise lstat works like stat. See Section 14.5 [Symbolic Links], page 357.
When the sources are compiled with _FILE_OFFSET_BITS == 64 this function is in fact
lstat64 since the LFS interface transparently replaces the normal implementation.
一旦给出pathname,stat函数就返回与此命名有关的信息结构,fstat函数获取已在描述符filedes上打开文件的有关信息。lstat函数类似于stat,但是当命名文件时一个符号链接,lstat返回该符号链接的有关信息。而不是有该符号引用文的信息。
第二个参数是buf,指针。指向我们必须提供的结构。
- 应用一:判断文件(文件夹)是否可读、可写、可执行:
判断文件(文件夹)是否可读的函数:
- #include <sys/unistd.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- /** /brief 判断文件(文件夹)在当前上下文环境下是否可读
- *
- * /param const char* _path: 文件或文件夹的路径,可以为绝对路径或相对路径
- * /return signed char
- * 1:可读;
- * 0:不可读;
- * -1:错误,错误号可以从全局的errno获取;
- */
- signed char canRead(constchar* _path)
- {
- struct stat buff;
- if(stat(_path,&buff) == 0)
- {
- /**当前用户为root,当然拥有读的权限*/
- if(0 == geteuid())
- {
- return 1;
- }
- /**当前用户为该文件(文件夹)的所有者,判断是否有所有者可读权限*/
- else if(buff.st_uid == geteuid())
- {
- return ((buff.st_mode & S_IRUSR != 0)?1 : 0);
- }
- /**当前用户组为该文件(文件夹)的用户组,判断是否有用户组可读权限*/
- else if(buff.st_gid == getegid())
- {
- return ((buff.st_mode & S_IRGRP != 0)?1 : 0);
- }
- /**判断其他人是否有可读权限*/
- else
- {
- return ((buff.st_mode & S_IROTH != 0)?1 : 0);
- }
- }
- else
- {
- return -1;
- }
- }
函数的过程很简单,判断逻辑在注释中也写的很清楚了,需要包含的头文件:
#include <sys/unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
利用这个思路,判断可写,判断可运行的函数就很容易写出了。
下面是判断文件(文件夹)是否可写的函数:
- #include <sys/unistd.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- /** /brief 判断文件(文件夹)在当前上下文环境下是否可写
- *
- * /param const char* _path: 文件或文件夹的路径,可以为绝对路径或相对路径
- * /return signed char
- * 1:可读;
- * 0:不可读;
- * -1:错误,错误号可以从全局的errno获取;
- */
- signed char canWrite(constchar* _path)
- {
- struct stat buff;
- if(stat(_path,&buff) == 0)
- {
- /**当前用户为root,当然拥有写的权限*/
- if(0 == geteuid())
- {
- return 1;
- }
- /**当前用户为该文件(文件夹)的所有者,判断是否有所有者可写权限*/
- else if(buff.st_uid == geteuid())
- {
- return ((buff.st_mode & S_IWUSR != 0)?1 : 0);
- }
- /**当前用户组为该文件(文件夹)的用户组,判断是否有用户组可写权限*/
- else if(buff.st_gid == getegid())
- {
- return ((buff.st_mode & S_IWGRP != 0)?1 : 0);
- }
- /**判断其他人是否有可读权限*/
- else
- {
- return ((buff.st_mode & S_IWOTH != 0)?1 : 0);
- }
- }
- else
- {
- return -1;
- }
- }
下面是判断文件(文件夹)是否可运行的函数:
- #include <sys/unistd.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- /** /brief 判断文件(文件夹)在当前上下文环境下是否可执行
- *
- * /param const char* _path: 文件或文件夹的路径,可以为绝对路径或相对路径
- * /return signed char
- * 1:可读;
- * 0:不可读;
- * -1:错误,错误号可以从全局的errno获取;
- */
- signed char canExecute(constchar* _path)
- {
- struct stat buff;
- if(stat(_path,&buff) == 0)
- {
- /**当前用户为root,当然拥有读的权限*/
- if(0 == geteuid())
- {
- return 1;
- }
- /**当前用户为该文件(文件夹)的所有者,判断是否有所有者可执行权限*/
- else if(buff.st_uid == geteuid())
- {
- return ((buff.st_mode & S_IXUSR != 0)?1 : 0);
- }
- /**当前用户组为该文件(文件夹)的用户组,判断是否有用户组可执行权限*/
- else if(buff.st_gid == getegid())
- {
- return ((buff.st_mode & S_IXGRP != 0)?1 : 0);
- }
- /**判断其他人是否有可执行权限*/
- else
- {
- return ((buff.st_mode & S_IXOTH != 0)?1 : 0);
- }
- }
- else
- {
- return -1;
- }
- }
- 应用二:获得文件(文件夹)的大小
对于普通文件来说,获取文件占用的大小很简单,只需要返回结构体stat的st_sizee即可。但是对于文件夹来说,结构体stat的st_size表明的是文件夹本身占用的空间大小(在Linux文件体系中,对于文件夹来说是需要空间来存储自身文件夹下的文件或文件夹的inode号的),与我们普遍意义上理解的文件夹应该返回的是其包含文件或文件夹的总容量不同,因此需要设计一个函数来获得文件夹下所有文件(文件夹)的总容量:
- #include <sys/unistd.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <dirent.h>
- #include <string>
- /** /brief 获得文件夹的总大小
- *
- * /param const char* _path: 文件夹的路径,可以为绝对路径或相对路径
- * /return off_t
- * 返回路径指向文件夹的总容量;
- */
- off_t getDirTotalSize(constchar* _path)
- {
- struct dirent* ent(0);
- DIR* pDir(opendir(_path));
- off_t result(0);
- char buff[512] = {0};
- while ((ent = readdir(pDir)) != 0)
- {
- /**在Linux文件系统中 .和..也是特殊的子目录,明显这里不应该计算*/
- if(strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0)
- {
- continue;
- }
- sprintf(buff, "%s/%s", _path, ent->d_name);
- /**如果当前是目录 则递归计算子目录的大小*/
- if (ent->d_type == DT_DIR)
- {
- result += getDirTotalSize(buff);
- }
- else
- {
- result += getFileSize(buff);
- }
- }
- return result;
- }
- /** /brief 获得文件的大小
- *
- * /param const char* _path: 文件的路径,可以为绝对路径或相对路径
- * /return off_t
- * 成功则返回路径指向文件的大小;
- * -1:错误,错误号可以从全局的errno获取;
- */
- off_t getFileSize(const char* _path)
- {
- struct stat buff;
- if (stat(_path, &buff) == 0)
- {
- return buff.st_size;
- }
- else
- {
- return -1;
- }
- }
其实更加通用的遍历目录函数可以这样设计:用注册回调函数的方法来实现,这个回调函数的参数就是每个遍历项的路径(最好是绝对路径),那么以后遍历目录就不需要改变了 只需要在应用中注册不同的回调函数就可以了。实现如下:
- #include <sys/unistd.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <dirent.h>
- #include <string>
- #include <stdio.h>
- off_t getFileSize(const char* _path);
- void traverseDir(constchar* _path,off_t(*_callPtr)(constchar*),void(*_callbackResPtr)(off_t) = 0);
- void sumSize(off_t _size);
- /**< 计算的文件夹大小结果 */
- off_t result(0);
- int main(int argc,char** argv)
- {
- traverseDir(*(++argv),getFileSize,sumSize);
- printf("%ld", result);
- return 0;
- }
- /** /brief 递归遍历目录,并在遇到非文件夹时
- * 调用回调函数off_t(*_callPtr)(const char*) 参数为当前的绝对路径
- *
- * /param const char* _path: 需要遍历的文件夹的路径,可以为绝对路径或相对路径
- * /param off_t(*_callPtr)(const char*):
- * 需要遍历的文件夹的路径,可以为绝对路径或相对路径
- * /param void(*_callbackResPtr)(off_t):
- * 以每次调用完_callPtr后的返回值为参数的回调函数,默认值为0,
- * 表示不对每次调用_callPtr的结果感兴趣
- * /return void
- */
- void traverseDir(constchar* _path,off_t(*_callPtr)(constchar*),void(*_callbackResPtr)(off_t))
- {
- struct dirent* ent(0);
- DIR* pDir(opendir(_path));
- char buff[512] = {0};
- while ((ent = readdir(pDir)) != 0)
- {
- /**在Linux文件系统中 .和..也是特殊的子目录,明显这里不应该递归*/
- if(strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0)
- {
- continue;
- }
- sprintf(buff, "%s/%s", _path, ent->d_name);
- /**如果当前是目录 则递归子目录*/
- if (ent->d_type == DT_DIR)
- {
- traverseDir(buff,_callPtr,_callbackResPtr);
- }
- else
- {
- if(_callbackResPtr)
- {
- (*_callbackResPtr)( (*_callPtr)(buff) );
- }
- else
- {
- (*_callPtr)(buff);
- }
- }
- }
- return;
- }
- /** /brief 获得文件的大小
- *
- * /param const char* _path: 文件的路径,可以为绝对路径或相对路径
- * /return off_t
- * 成功则返回路径指向文件的大小;
- * -1:错误,错误号可以从全局的errno获取;
- */
- off_t getFileSize(const char* _path)
- {
- struct stat buff;
- if (stat(_path, &buff) == 0)
- {
- return buff.st_size;
- }
- else
- {
- return -1;
- }
- }
- /** /brief 一个简单的统计,把每次传入的数值累加起来 赋值到result上
- *
- * /param off_t _size: 文件的大小
- * /return void
- */
- void sumSize(off_t _size)
- {
- result += _size;
- return;
- }
这种实现方式的优势是利用回调函数,遍历文件夹的操作可以复用,缺点是如果需要统计每次回调函数的结果就需要额外的一个全局参数(当然可以用命名空间的方式局部化。。。)。利用这种方式,还能方便的实现出统计文件夹下各种文件类型的数量,属于某个用户ID文件的数量等等(改改两个回调函数就行了)。
- 应用三:获得文件(文件夹)的三个时间:最后访问(读)时间、最后修改(写)时间、创建时间或最后更改(属性更改)时间
在项目中,我们经常会需要获得文件(文件夹)的最后访问(读)时间、最后修改(写)时间、创建时间或最后更改(属性更改)时间这三种时间,在Linux中,触发这三种时间改变的条件分别是:
最后访问(读)时间:文件(文件夹)最后一次被存取或执行的时间;
最后修改(写)时间:文件(文件夹)最后一次被修改的时间,这里指的修改是内容上的;
创建时间或最后更改(属性更改)时间:文件(文件夹)最后一次被更改的时间,这里指的修改是属性上的,如所有者、权限等;
对应到结构体stat上就是:
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
值得一提的是,以上三种时间在Linux中是用UTC表示的,单位是秒,举个例子:1285328411表示的是从1970年1月1日开始所经过的秒数,值得注意的是这里的时间是UTC时间。
这里仅用最后访问(读)时间为例:
- #include <sys/unistd.h>
- #include <sys/stat.h>
- /** /brief 判断文件(文件夹)的最后访问时间
- *
- * /param const char* _path: 文件或文件夹的路径,可以为绝对路径或相对路径
- * /return time_t
- * >0:成功;
- * 0:错误;
- */
- time_t getReadTime(constchar* _path)
- {
- struct stat buff;
- if(stat(_path,&buff) == 0)
- {
- return buff.st_atime;
- }
- return 0;
- }
另外两种时间的获取方式,就当作小练习吧。
- 应用四:获得文件类型
最后来谈谈如何根据st_mode来判断文件(文件夹)的类型,这里可以利用库本身就定义好的一些宏:
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) /**文件夹的判断*/
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) /**管道文件的判断*/
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) /**字符设备的判断*/
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) /**块设备的判断*/
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) /**普通文件的判断*/
实例如下:
- #include <sys/unistd.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- /** /brief 判断文件(文件夹)的类型
- *
- * /param const char* _path: 文件或文件夹的路径,可以为绝对路径或相对路径
- * /return signed char
- * 0:普通文件
- * 1:文件夹
- * 2:管道文件
- * 3:字符设备文件
- * 4:块设备文件
- * -1:错误,错误号可以从全局的errno获取;
- */
- signed char getFileType(constchar* _path)
- {
- struct stat buff;
- if(stat(_path,&buff) == 0)
- {
- if(S_ISREG(buff.st_mode))
- {
- return 0;
- }
- else if(S_ISDIR(buff.st_mode))
- {
- return 1;
- }
- else if(S_ISFIFO(buff.st_mode))
- {
- return 2;
- }
- else if(S_ISCHR(buff.st_mode))
- {
- return 3;
- }
- else if(S_ISBLK(buff.st_mode))
- {
- return 4;
- }
- else
- {
- return -1;
- }
- }
- else
- {
- return -1;
- }
- }
当然在项目中一般是不用硬编码的,可以定义相关的enum。
stat,fstate,lstat函数的更多相关文章
- C语言:stat,fstat和lstat函数
这三个函数的功能是一致的,都用于获取文件相关信息,但应用于不同的文件对象.对于函数中给出pathname参数,stat函数返回与此命名文件有关的信息结构,fstat函数获取已在描述符fields上打开 ...
- 文件和目录之stat、fstat和lstat函数
#include <sys/stat.h> int stat( const char *restrict pathname, struct stat *restrict buf ); in ...
- 第九篇:使用 lstat 函数获取文件信息
前言 在之前的文章中,描述过如何用 fcntl 函数改变文件的状态标记.但,文件还有很多信息,如文件类型,权限设置,设备编号,访问时间等等.如果要获取这些信息,则使用函数 lstat 可以轻松达到这个 ...
- 使用 lstat 函数获取文件信息
前言 在之前的文章中,描述过如何用 fcntl 函数改变文件的状态标记.但,文件还有很多信息,如文件类型,权限设置,设备编号,访问时间等等.如果要获取这些信息,则使用函数 lstat 可以轻松达到这个 ...
- lstat函数的使用【学习笔记】
通过lstat函数获取文件的类型的代码如下. #include "apue.h" int main(int argc,char *argv[]) { int i; struct s ...
- PHP lstat() 函数
定义和用法 lstat() 函数返回关于文件或符号连接的信息. 该函数将返回一个包含下列元素的数组: [0] 或 [dev] - 设备编号 [1] 或 [ino] - inode 编号 [2] 或 [ ...
- stat/lstat函数使用
1. 进程虚拟地址空间 2. stat函数 获取文件信息 #include <sys/types.h> #include <sys/stat.h> #include <u ...
- PHP常用函数大全
usleep() 函数延迟代码执行若干微秒.unpack() 函数从二进制字符串对数据进行解包.uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID.time_sleep_until() ...
- PHP常用函数备用
刚学习php的时候,我也为记忆php函数苦恼不已.认为干嘛记忆这么枯燥无味的东西呢?用的时候查一下手册不就行了吗?但是当时因为身在辅导机构,还是记忆了一大堆自己并不感兴趣的函数. 由此就想起来,小的时 ...
随机推荐
- CodeForces Contest #1114: Round #538 (Div. 2)
比赛传送门:CF #1114. 比赛记录:点我. 又 FST 了. [A]Got Any Grapes? 题意简述: 有三个人,第一个人需要吃绿色葡萄至少 \(a\) 个,第二个人需要吃绿色和紫色葡萄 ...
- 查看nginx | apache | php | tengine | tomcat版本的信息以及如何隐藏版本信息【转】
转自: 查看nginx | apache | php | tengine | tomcat版本的信息以及如何隐藏版本信息 - 追马 - 51CTO技术博客http://lovelace.blog.51 ...
- [cookie篇]cookie-parser之parser.js
cookie-parser的作用,官方的说法是:Parse Cookie header and populate req.cookies with an object keyed by the coo ...
- android调节声音大小
android调节声音大小 1.背景音乐的一些知识 网上好多关于背景音乐添加用到的类: MediaPlayer,SoundPool,AudioManager的资料,可是有时候解决不了我们在开发中遇到的 ...
- 0行代码实现任意形状图片展示--android-anyshape
前言 在Android开发中, 我们经常会遇到一些场景, 需要以一些特殊的形状显示图片, 比如圆角矩形.圆形等等.关于如何绘制这类形状, 网上已经有很多的方案,比如自定义控件重写onDraw方法, 通 ...
- Workman启动失败的解决方法 stream_socket_server() has been disabled for security reasons
1.报如下错误,问题是php版本太低 php -ini 看下你的版本 http://doc2.workerman.net/how-distributed.html 参考: https://blog.c ...
- Java编程的逻辑 (26) - 剖析包装类 (上)
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- 关于x509、crt、cer、key、csr、pem、der、ssl、tls 、openssl等
关于x509.crt.cer.key.csr.pem.der.ssl.tls .openssl等 TLS:传输层安全协议 Transport Layer Security的缩写 TLS是传输层安全协议 ...
- 024.Zabbix告警等级机制
一 等级告警 告警升级可以对告警结果按自定义的时间段进行进行消息发送,并执行命令,形成一个梯度的告警处理. 二 按时间自定义告警梯度 2.1 添加时间发生的时间戳和发送时间 2.2 设置三个等级梯度 ...
- maven deploy上传私服出错
error 内容如下 Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.5: deploy (default ...