1. #include <sys/stat.h>
  2. int stat (const char *restrict pathname,struct stat* restrict buf)
  3. int fstat(int filedes,struct stat *buf);
  4. 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,指针。指向我们必须提供的结构。

  •    应用一:判断文件(文件夹)是否可读、可写、可执行:

    判断文件(文件夹)是否可读的函数:

   

  1. #include <sys/unistd.h> 
  2. #include <sys/stat.h> 
  3. #include <sys/types.h> 
  4.  
  5. /** /brief 判断文件(文件夹)在当前上下文环境下是否可读
  6. *
  7. * /param const char* _path: 文件或文件夹的路径,可以为绝对路径或相对路径
  8. * /return signed char
  9. *  1:可读;
  10. *  0:不可读;
  11. * -1:错误,错误号可以从全局的errno获取;
  12. */ 
  13. signed char canRead(constchar* _path) 
  14.     struct stat buff; 
  15.     if(stat(_path,&buff) == 0) 
  16.     { 
  17.         /**当前用户为root,当然拥有读的权限*/ 
  18.         if(0 == geteuid()) 
  19.         { 
  20.             return 1; 
  21.         } 
  22.         /**当前用户为该文件(文件夹)的所有者,判断是否有所有者可读权限*/ 
  23.         else if(buff.st_uid == geteuid()) 
  24.         { 
  25.             return ((buff.st_mode & S_IRUSR != 0)?1 : 0); 
  26.         } 
  27.         /**当前用户组为该文件(文件夹)的用户组,判断是否有用户组可读权限*/ 
  28.         else if(buff.st_gid == getegid()) 
  29.         { 
  30.             return ((buff.st_mode & S_IRGRP != 0)?1 : 0); 
  31.         } 
  32.         /**判断其他人是否有可读权限*/ 
  33.         else 
  34.         { 
  35.             return ((buff.st_mode & S_IROTH != 0)?1 : 0); 
  36.         } 
  37.     } 
  38.     else 
  39.     { 
  40.         return -1; 
  41.     } 

     函数的过程很简单,判断逻辑在注释中也写的很清楚了,需要包含的头文件:

    #include <sys/unistd.h>
    #include <sys/stat.h>
    #include <sys/types.h>

    利用这个思路,判断可写,判断可运行的函数就很容易写出了。

下面是判断文件(文件夹)是否可写的函数:

  

  1. #include <sys/unistd.h> 
  2. #include <sys/stat.h> 
  3. #include <sys/types.h> 
  4.  
  5. /** /brief 判断文件(文件夹)在当前上下文环境下是否可写
  6. *
  7. * /param const char* _path: 文件或文件夹的路径,可以为绝对路径或相对路径
  8. * /return signed char
  9. *  1:可读;
  10. *  0:不可读;
  11. * -1:错误,错误号可以从全局的errno获取;
  12. */ 
  13. signed char canWrite(constchar* _path) 
  14.     struct stat buff; 
  15.     if(stat(_path,&buff) == 0) 
  16.     { 
  17.         /**当前用户为root,当然拥有写的权限*/ 
  18.         if(0 == geteuid()) 
  19.         { 
  20.             return 1; 
  21.         } 
  22.         /**当前用户为该文件(文件夹)的所有者,判断是否有所有者可写权限*/ 
  23.         else if(buff.st_uid == geteuid()) 
  24.         { 
  25.             return ((buff.st_mode & S_IWUSR != 0)?1 : 0); 
  26.         } 
  27.         /**当前用户组为该文件(文件夹)的用户组,判断是否有用户组可写权限*/ 
  28.         else if(buff.st_gid == getegid()) 
  29.         { 
  30.             return ((buff.st_mode & S_IWGRP != 0)?1 : 0); 
  31.         } 
  32.         /**判断其他人是否有可读权限*/ 
  33.         else 
  34.         { 
  35.             return ((buff.st_mode & S_IWOTH != 0)?1 : 0); 
  36.         } 
  37.     } 
  38.     else 
  39.     { 
  40.         return -1; 
  41.     } 

    下面是判断文件(文件夹)是否可运行的函数:

  

  1. #include <sys/unistd.h> 
  2. #include <sys/stat.h> 
  3. #include <sys/types.h> 
  4.  
  5. /** /brief 判断文件(文件夹)在当前上下文环境下是否可执行
  6. *
  7. * /param const char* _path: 文件或文件夹的路径,可以为绝对路径或相对路径
  8. * /return signed char
  9. *  1:可读;
  10. *  0:不可读;
  11. * -1:错误,错误号可以从全局的errno获取;
  12. */ 
  13. signed char canExecute(constchar* _path) 
  14.     struct stat buff; 
  15.     if(stat(_path,&buff) == 0) 
  16.     { 
  17.         /**当前用户为root,当然拥有读的权限*/ 
  18.         if(0 == geteuid()) 
  19.         { 
  20.             return 1; 
  21.         } 
  22.         /**当前用户为该文件(文件夹)的所有者,判断是否有所有者可执行权限*/ 
  23.         else if(buff.st_uid == geteuid()) 
  24.         { 
  25.             return ((buff.st_mode & S_IXUSR != 0)?1 : 0); 
  26.         } 
  27.         /**当前用户组为该文件(文件夹)的用户组,判断是否有用户组可执行权限*/ 
  28.         else if(buff.st_gid == getegid()) 
  29.         { 
  30.             return ((buff.st_mode & S_IXGRP != 0)?1 : 0); 
  31.         } 
  32.         /**判断其他人是否有可执行权限*/ 
  33.         else 
  34.         { 
  35.             return ((buff.st_mode & S_IXOTH != 0)?1 : 0); 
  36.         } 
  37.     } 
  38.     else 
  39.     { 
  40.         return -1; 
  41.     } 
  •    应用二:获得文件(文件夹)的大小

对于普通文件来说,获取文件占用的大小很简单,只需要返回结构体stat的st_sizee即可。但是对于文件夹来说,结构体stat的st_size表明的是文件夹本身占用的空间大小(在Linux文件体系中,对于文件夹来说是需要空间来存储自身文件夹下的文件或文件夹的inode号的),与我们普遍意义上理解的文件夹应该返回的是其包含文件或文件夹的总容量不同,因此需要设计一个函数来获得文件夹下所有文件(文件夹)的总容量:

  1. #include <sys/unistd.h>
  2. #include <sys/stat.h>
  3. #include <sys/types.h>
  4. #include <dirent.h>
  5. #include <string>
  6. /** /brief 获得文件夹的总大小
  7. *
  8. * /param const char* _path: 文件夹的路径,可以为绝对路径或相对路径
  9. * /return off_t
  10. * 返回路径指向文件夹的总容量;
  11. */
  12. off_t getDirTotalSize(constchar* _path)
  13. {
  14. struct dirent* ent(0);
  15. DIR* pDir(opendir(_path));
  16. off_t result(0);
  17. char buff[512] = {0};
  18. while ((ent = readdir(pDir)) != 0)
  19. {
  20. /**在Linux文件系统中 .和..也是特殊的子目录,明显这里不应该计算*/
  21. if(strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0)
  22. {
  23. continue;
  24. }
  25. sprintf(buff, "%s/%s", _path, ent->d_name);
  26. /**如果当前是目录 则递归计算子目录的大小*/
  27. if (ent->d_type == DT_DIR)
  28. {
  29. result += getDirTotalSize(buff);
  30. }
  31. else
  32. {
  33. result += getFileSize(buff);
  34. }
  35. }
  36. return result;
  37. }
  38. /** /brief 获得文件的大小
  39. *
  40. * /param const char* _path: 文件的路径,可以为绝对路径或相对路径
  41. * /return off_t
  42. * 成功则返回路径指向文件的大小;
  43. * -1:错误,错误号可以从全局的errno获取;
  44. */
  45. off_t getFileSize(const char* _path)
  46. {
  47. struct stat buff;
  48. if (stat(_path, &buff) == 0)
  49. {
  50. return buff.st_size;
  51. }
  52. else
  53. {
  54. return -1;
  55. }
  56. }

其实更加通用的遍历目录函数可以这样设计:用注册回调函数的方法来实现,这个回调函数的参数就是每个遍历项的路径(最好是绝对路径),那么以后遍历目录就不需要改变了 只需要在应用中注册不同的回调函数就可以了。实现如下:

  1. #include <sys/unistd.h>
  2. #include <sys/stat.h>
  3. #include <sys/types.h>
  4. #include <dirent.h>
  5. #include <string>
  6. #include <stdio.h>
  7. off_t getFileSize(const char* _path);
  8. void traverseDir(constchar* _path,off_t(*_callPtr)(constchar*),void(*_callbackResPtr)(off_t) = 0);
  9. void sumSize(off_t _size);
  10. /**< 计算的文件夹大小结果 */
  11. off_t result(0);
  12. int main(int argc,char** argv)
  13. {
  14. traverseDir(*(++argv),getFileSize,sumSize);
  15. printf("%ld", result);
  16. return 0;
  17. }
  18. /** /brief 递归遍历目录,并在遇到非文件夹时
  19. *  调用回调函数off_t(*_callPtr)(const char*) 参数为当前的绝对路径
  20. *
  21. * /param const char* _path: 需要遍历的文件夹的路径,可以为绝对路径或相对路径
  22. * /param off_t(*_callPtr)(const char*):
  23. * 需要遍历的文件夹的路径,可以为绝对路径或相对路径
  24. * /param void(*_callbackResPtr)(off_t):
  25. * 以每次调用完_callPtr后的返回值为参数的回调函数,默认值为0,
  26. *  表示不对每次调用_callPtr的结果感兴趣
  27. * /return void
  28. */
  29. void traverseDir(constchar* _path,off_t(*_callPtr)(constchar*),void(*_callbackResPtr)(off_t))
  30. {
  31. struct dirent* ent(0);
  32. DIR* pDir(opendir(_path));
  33. char buff[512] = {0};
  34. while ((ent = readdir(pDir)) != 0)
  35. {
  36. /**在Linux文件系统中 .和..也是特殊的子目录,明显这里不应该递归*/
  37. if(strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0)
  38. {
  39. continue;
  40. }
  41. sprintf(buff, "%s/%s", _path, ent->d_name);
  42. /**如果当前是目录 则递归子目录*/
  43. if (ent->d_type == DT_DIR)
  44. {
  45. traverseDir(buff,_callPtr,_callbackResPtr);
  46. }
  47. else
  48. {
  49. if(_callbackResPtr)
  50. {
  51. (*_callbackResPtr)( (*_callPtr)(buff) );
  52. }
  53. else
  54. {
  55. (*_callPtr)(buff);
  56. }
  57. }
  58. }
  59. return;
  60. }
  61. /** /brief 获得文件的大小
  62. *
  63. * /param const char* _path: 文件的路径,可以为绝对路径或相对路径
  64. * /return off_t
  65. * 成功则返回路径指向文件的大小;
  66. * -1:错误,错误号可以从全局的errno获取;
  67. */
  68. off_t getFileSize(const char* _path)
  69. {
  70. struct stat buff;
  71. if (stat(_path, &buff) == 0)
  72. {
  73. return buff.st_size;
  74. }
  75. else
  76. {
  77. return -1;
  78. }
  79. }
  80. /** /brief 一个简单的统计,把每次传入的数值累加起来 赋值到result上
  81. *
  82. * /param off_t _size: 文件的大小
  83. * /return void
  84. */
  85. void sumSize(off_t _size)
  86. {
  87. result += _size;
  88. return;
  89. }

这种实现方式的优势是利用回调函数,遍历文件夹的操作可以复用,缺点是如果需要统计每次回调函数的结果就需要额外的一个全局参数(当然可以用命名空间的方式局部化。。。)。利用这种方式,还能方便的实现出统计文件夹下各种文件类型的数量,属于某个用户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时间。

这里仅用最后访问(读)时间为例:

  1. #include <sys/unistd.h>
  2. #include <sys/stat.h>
  3. /** /brief 判断文件(文件夹)的最后访问时间
  4. *
  5. * /param const char* _path: 文件或文件夹的路径,可以为绝对路径或相对路径
  6. * /return time_t
  7. *  >0:成功;
  8. *  0:错误;
  9. */
  10. time_t getReadTime(constchar* _path)
  11. {
  12. struct stat buff;
  13. if(stat(_path,&buff) == 0)
  14. {
  15. return buff.st_atime;
  16. }
  17. return 0;
  18. }

另外两种时间的获取方式,就当作小练习吧。

  • 应用四:获得文件类型

最后来谈谈如何根据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) /**普通文件的判断*/

实例如下:

  1. #include <sys/unistd.h>
  2. #include <sys/stat.h>
  3. #include <sys/types.h>
  4. /** /brief 判断文件(文件夹)的类型
  5. *
  6. * /param const char* _path: 文件或文件夹的路径,可以为绝对路径或相对路径
  7. * /return signed char
  8. *  0:普通文件
  9. *  1:文件夹
  10. *  2:管道文件
  11. *  3:字符设备文件
  12. *  4:块设备文件
  13. * -1:错误,错误号可以从全局的errno获取;
  14. */
  15. signed char getFileType(constchar* _path)
  16. {
  17. struct stat buff;
  18. if(stat(_path,&buff) == 0)
  19. {
  20. if(S_ISREG(buff.st_mode))
  21. {
  22. return 0;
  23. }
  24. else if(S_ISDIR(buff.st_mode))
  25. {
  26. return 1;
  27. }
  28. else if(S_ISFIFO(buff.st_mode))
  29. {
  30. return 2;
  31. }
  32. else if(S_ISCHR(buff.st_mode))
  33. {
  34. return 3;
  35. }
  36. else if(S_ISBLK(buff.st_mode))
  37. {
  38. return 4;
  39. }
  40. else
  41. {
  42. return -1;
  43. }
  44. }
  45. else
  46. {
  47. return -1;
  48. }
  49. }

当然在项目中一般是不用硬编码的,可以定义相关的enum。

stat,fstate,lstat函数的更多相关文章

  1. C语言:stat,fstat和lstat函数

    这三个函数的功能是一致的,都用于获取文件相关信息,但应用于不同的文件对象.对于函数中给出pathname参数,stat函数返回与此命名文件有关的信息结构,fstat函数获取已在描述符fields上打开 ...

  2. 文件和目录之stat、fstat和lstat函数

    #include <sys/stat.h> int stat( const char *restrict pathname, struct stat *restrict buf ); in ...

  3. 第九篇:使用 lstat 函数获取文件信息

    前言 在之前的文章中,描述过如何用 fcntl 函数改变文件的状态标记.但,文件还有很多信息,如文件类型,权限设置,设备编号,访问时间等等.如果要获取这些信息,则使用函数 lstat 可以轻松达到这个 ...

  4. 使用 lstat 函数获取文件信息

    前言 在之前的文章中,描述过如何用 fcntl 函数改变文件的状态标记.但,文件还有很多信息,如文件类型,权限设置,设备编号,访问时间等等.如果要获取这些信息,则使用函数 lstat 可以轻松达到这个 ...

  5. lstat函数的使用【学习笔记】

    通过lstat函数获取文件的类型的代码如下. #include "apue.h" int main(int argc,char *argv[]) { int i; struct s ...

  6. PHP lstat() 函数

    定义和用法 lstat() 函数返回关于文件或符号连接的信息. 该函数将返回一个包含下列元素的数组: [0] 或 [dev] - 设备编号 [1] 或 [ino] - inode 编号 [2] 或 [ ...

  7. stat/lstat函数使用

    1. 进程虚拟地址空间 2. stat函数 获取文件信息 #include <sys/types.h> #include <sys/stat.h> #include <u ...

  8. PHP常用函数大全

    usleep() 函数延迟代码执行若干微秒.unpack() 函数从二进制字符串对数据进行解包.uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID.time_sleep_until() ...

  9. PHP常用函数备用

    刚学习php的时候,我也为记忆php函数苦恼不已.认为干嘛记忆这么枯燥无味的东西呢?用的时候查一下手册不就行了吗?但是当时因为身在辅导机构,还是记忆了一大堆自己并不感兴趣的函数. 由此就想起来,小的时 ...

随机推荐

  1. c# 获取百度最后的url

    using System;using System.Collections.Generic;using System.Linq;using System.Net.Http;using System.T ...

  2. windows下使用pip安装python模块lxml

    pip install lxml 1 1 会有如下问题:  结果一路解决下去,解决了一个坑还是有一个坑,遂放弃,查找有没有别的解决办法. 亲测使用wheel+pip可以成功安装lxml! wheel本 ...

  3. 自定义Web组件

    一.Session 1.面向对象基础 面向对象中通过索引的方式访问对象,需要内部实现 __getitem__ .__delitem__.__setitem__方法 +? 1 2 3 4 5 6 7 8 ...

  4. RandomForest随机森林总结

    1.随机森林原理介绍 随机森林,指的是利用多棵树对样本进行训练并预测的一种分类器.该分类器最早由Leo Breiman和Adele Cutler提出,并被注册成了商标.简单来说,随机森林就是由多棵CA ...

  5. Android 插件化 开发

    插件化知识详细分解及原理 之Binder机制https://blog.csdn.net/yulong0809/article/details/56841993 插件化知识详细分解及原理 之代理,hoo ...

  6. yum源安装php报错缺少libmcrypt.so.4()(64bit)库

    https://blog.csdn.net/programercch/article/details/56282184

  7. nginx log 错误502 upstream sent too big header while reading response header from upstream

    cookies的值超出了范围我是说 看看了一下日志 错误502 upstream sent too big header while reading response header from upst ...

  8. Java 中的 protected 访问修饰符你真的了解吗?

    protected Java 中的 protected 访问修饰符 总结 在同一个包中,类中 protected 或 default 修饰的属性或方法可以在类外被其对象 (实例) 外部访问,也可以被子 ...

  9. vue播放video插件vue-video-player实现hls, rtmp播放全过程

    1.安装插件 1 npm install vue-video-player -S 2.配置插件 在main.js里添加 1 import VideoPlayer from 'vue-video-pla ...

  10. [Java/Python] java调用python脚本问题记录

    Java调用Python的的两种方式 1.Runtime private static String call_python(String input_argv) { String python_py ...