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. CSS text系列

    text-shadow 语法规则: h-shadow(必需,水平阴影的位置,可负): v-shadow(必需,垂直阴影的位置,可负): blur(可选,模糊距离): color(可选,阴影的颜色). ...

  2. Linux入侵问题排查

    1.深入分析,查找入侵原因 1.1 检查隐藏账户及弱口令 1.1.1.检查服务器系统及应用账户是否存在弱口令 检查说明:检查管理员账户.数据库账户.MySQL账户.tomcat账户.网站后台管理员账户 ...

  3. 浅谈tomcat中间件的优化【转】

    今天来总结一下tomcat的一些优化的方案,由于本人才疏学浅,写的不好,勿喷! tomcat对于大多数从事开发工作的童鞋应该不会很陌生,通常做为默认的开发环境来为大家服务,不过tomcat默认的一些配 ...

  4. H5新增语义化标签

    一.根据页面的结构,由div派生的标签. <header> <footer> <nav> 导航 在H4中导航栏一般用ul-li标签,H5中可以直接用<nav& ...

  5. POJ 1948 Triangular Pastures

    题意: 把很多单独的线段重新组合成一个三角形,使得三角形面积最大(所有的线段都必须用上). 思路: 三角形的任意一条边的边长不能超过周长的一半,只需要用dp枚举两条边j,k,剩下的一条边长为tot  ...

  6. Linix下修改mysql服务器编码

    1. 找到mysql的配置文件,拷贝到etc目录下,第一步很重要 把/usr/share/doc/mysql-server-5.1.52/my-large.cnf 复制到 /etc/my.cnf 即用 ...

  7. Java编程的逻辑 (5) - 小数计算为什么会出错?

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  8. Java第三阶段学习(十一、Servlet基础、servlet中的方法、servlet的配置、ServletContext对象)

    一.Servlet简介  1.什么是servlet: sun公司提供的一套规范(接口),用来处理客户端请求.响应给浏览器的动态资源.但servlet的实质就是java代码,通过java的API动态的向 ...

  9. TFC2017 腾讯Web前端大会参会小结

    简述 上周有幸参加TFC腾讯Web前端大会,见识了各路前端大神的精彩演讲,干货满满的.会议流程分为上午主会场,以及下午的三个分会场.分享的主题涵盖Web新技术.Node.js.框架.工程化. 图形处理 ...

  10. 【LOJ】#6437. 「PKUSC2018」PKUSC

    题解 我们把这个多边形三角形剖分了,和统计多边形面积一样 每个三角形有个点是原点,把原点所对应的角度算出来,记为theta 对于一个点,相当于半径为这个点到原点的一个圆,圆弧上的弧度为theta的一部 ...