工作中涉及到文件系统,有时候需要判断文件和目录是否存在,下面是一些前人的经验分享。


判断文件存在

对于判断文件是否存在,每个人有不同的方法!我通常采用两种方法 : open 和 access ;

这个俩个方法有相似之处,且有不同之处;下面为大家详细说明他们的不同之处:

open 是打开,读写等操作文件的一个函数,access就是一个判断文件权限的函数。在Linux下,由于文件有不同的权限,当当前用户没有对此文件的读权限的时候,用来判断文件是否存在,显然不合适。而access却可以做到。

open 的第一个参数是文件路径,第二个参数是打开文件选项,常用的有O_RDONLY(读),O_WRONLY(写),O_RDWR(读写),O_CREAT(创建)。 第三个参数通常在创建文件的时候才使用,给文件设定权限使用。

access的第一个参数是文件路径,第二个参数是测试的模式。常用的有R_OK:测试读权限,W_OK:测试写权限,X_OK:测试执行权限,F_OK:测试文件是否存在;

access函数

  access函数按照实际用户ID和实际组进行访问权限测试。函数原型为:

#include <unistd.h>
int access(const char *pathname, int mode);

mode取值:

F_OK  测试文件是否存在

R_OK  测试读权限

W_OK  测试写权限

X_OK  测试执行权限

正确判断一个文件是否存在是用access函数,实现如下所示:

#include <unistd.h>

int is_file_exist(const char *file_path)
{
    if(file_path == NULL)
        return -1;

    if( access(file_path, F_OK) == 0 )
        return 0;
    return -1;
}

我做个例子,写一个小程序来看两者的区别。
测试测序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc , char **argv)
{
char path[50];
memset(path,0,50);
sprintf(path,"%s","./test");
int fd;

printf("access function -------------------------/n");

if((fd = access (path,F_OK)) == 0)
printf("[access] file exist!/n");    
else    
printf("[access] file not exist!!/n");

if((fd = access (path,R_OK)) == 0)
printf("[access] read file ok!/n");
else    
printf("[access] read file no!/n");

if((fd = access (path,W_OK)) == 0)
printf("[access] write file ok!/n");
else    
printf("[access] write file no!/n");

if((fd = access (path,X_OK)) == 0)
printf("[access] execute file ok!/n");
else    
printf("[access] execute file no!/n");

printf("open  function -------------------------/n");


if((fd = open (path,O_RDONLY)) == -1)
printf("[open] open no!/n");
else    
{
close(fd);
printf("[open] open ok!/n");
}

if((fd = open (path,O_WRONLY)) == -1)
printf("[open] write no!/n");
else    
{
close(fd);
printf("[open] write ok!/n");
}
if((fd = open (path,O_RDWR)) == -1)
printf("[open] rdwr no!/n");
else    
{
close(fd);
printf("[open] rdwr ok!/n");
}
}

首先我们创建一个普通文件 test , 修改文件权限为0744,修改文件属主为root. 我们在普通用户mpeg4下操作.

[mpeg4@mc2800 file1]$ sudo chown root:root test
[mpeg4@mc2800 file1]$ sudo chmod 0744 test
[mpeg4@mc2800 file1]$ ls -l
total 20
-rwxrwxrwx 1 mpeg4 mpeg4 7157 2009-09-17 09:37 file
-rwxrwxrwx 1 mpeg4 mpeg4  991 2009-09-17 09:44 file.c
-rwxrwxrwx 1 mpeg4 mpeg4   94 2009-09-17 08:56 makefile
-rwxrwxrwx 1 mpeg4 mpeg4 3808 2009-08-20 13:52 records
-rwxr--r-- 1 root  root     0 2009-09-17 10:06 test

好了,我们运行我的程序看结果:

[mpeg4@mc2800 file1]$ ./file
access function -------------------------
[access] file exist!
[access] read file ok!
[access] write file no!
[access] execute file no!
open  function -------------------------
[open] open ok!
[open] write no!
[open] rdwr no!

很明显在用户有读权限的情况下,使用那个函数用来判断文件是否存在都可以。
现在我们把文件的权限改为0740:

sudo chmod 0740 test

再看测试结果:

[mpeg4@mc2800 file1]$ ./file
access function -------------------------
[access] file exist!
[access] read file no!
[access] write file no!
[access] execute file no!
open  function -------------------------
[open] open no!
[open] write no!
[open] rdwr no!

可以看到,文件权限改变了,就不能用open函数来判断文件是否存在了。

我相信很多人都喜欢用open函数来判断文件是否存在,当然大家也都知道关于权限的问题,所以会采用一些必要测措施来控制出错。但是我建议判断文件是否存在最好用access函数。当我们要读取文件内容的时候可以使用open来判断文件是否存在,就算是因为没有读权限或者文件真的不存在,都无法实现读的操作,我们的目的也就达到了。

stat系列函数

  stat函数用来返回与文件有关的结构信息。stat系列函数有三种情况,分别对应文件名称、文件描述符和符号链接文件。stat结构描述了文件的属性,主要包括文件的类型、文件大小等等。详细stat结构如下所示:

struct stat {
      mode_t    st_mode;    // file type & mode(permissions)
      ino_t     st_ino;     // i-node number(serial number)
      dev_t     st_dev;     // device number(filesystem)
      dev_t     st_rdev;    // device number for specials files
      nlink_t   st_nlink;   // number of links
      uid_t     st_uid;     // user ID of owner
      gid_t     st_gid;     // group ID of owner
      off_t     st_size;    // size in bytes, for regular files
      time_t    st_atime;   // time of last access
      time_t    st_mtime;   // time of last modification
      time_t    st_ctime;   // time of last file status change
      long      st_blksize; // best I/O block size
      long      st_blocks;  // number of 512-byte blocks allocated
   };

我们可以通过stat获取文件的类型和文件大小等信息。文件类型有:普通文件、目录文件、块特殊文件、字符特殊文件、FIFO、套接字和符号链接。要想通过stat系列函数来判断文件或者目录是否存在,当执行stat函数,如果文件存在时,还需进一步判断该文件是普通文件还是目录文件。

stat系列函数错误返回-1,错误码存在errno中,errno取值如下:

1、ENOENT 参数file_name 指定的文件不存在
2、ENOTDIR 路径中的目录存在但却非真正的目录
3、ELOOP 欲打开的文件有过多符号连接问题, 上限为16 符号连接
4、EFAULT 参数buf 为无效指针, 指向无法存在的内存空间
5、EACCESS 存取文件时被拒绝
6、ENOMEM 核心内存不足
7、ENAMETOOLONG 参数file_name 的路径名称太长

判断目录:oepndir函数

opendir函数用来打开文件目录,成功返回指针,出错返回NULL。
函数原型为:

#include <sys/types.h>
#include <dirent.h> 
DIR *opendir(const char *name);

实现如下:

#include <sys/types.h>
#include <dirent.h>

int is_dir_exist(const char *dir_path)
{
    DIR *dirptr = NULL;

    if(dir_path== NULL)
        return -1;

    if( dirptr=opendir(dir_path) == 0 ){
        return -1;
    }
    closedir(dirptr );
    return 0;
}