当前位置:  开发笔记 > 运维 > 正文

检查C中是否存在文件的最佳方法是什么?

如何解决《检查C中是否存在文件的最佳方法是什么?》经验,为你挑选了6个好方法。

有没有比简单地尝试打开文件更好的方法?

int exists(const char *fname)
{
    FILE *file;
    if ((file = fopen(fname, "r")))
    {
        fclose(file);
        return 1;
    }
    return 0;
}

Graeme Perro.. 542

查找access()功能,找到unistd.h.您可以用.替换您的功能

if( access( fname, F_OK ) != -1 ) {
    // file exists
} else {
    // file doesn't exist
}

你也可以使用R_OK,W_OK以及X_OK到位的F_OK检查读权限,写权限和执行(分别)的权限,而不是存在,你可以或任何他们在一起(即检查同时读取使用写权限R_OK|W_OK)

更新:请注意,在Windows上,您无法使用W_OK可靠地测试写入权限,因为访问功能不会考虑DACL.access( fname, W_OK )可能返回0(成功),因为该文件没有设置只读属性,但您仍然可能没有写入该文件的权限.



1> Graeme Perro..:

查找access()功能,找到unistd.h.您可以用.替换您的功能

if( access( fname, F_OK ) != -1 ) {
    // file exists
} else {
    // file doesn't exist
}

你也可以使用R_OK,W_OK以及X_OK到位的F_OK检查读权限,写权限和执行(分别)的权限,而不是存在,你可以或任何他们在一起(即检查同时读取使用写权限R_OK|W_OK)

更新:请注意,在Windows上,您无法使用W_OK可靠地测试写入权限,因为访问功能不会考虑DACL.access( fname, W_OK )可能返回0(成功),因为该文件没有设置只读属性,但您仍然可能没有写入该文件的权限.


POSIX是ISO标准; 它定义了access().C是另一个ISO标准; 它不是.
[...继续...]更确切地说,在POSIX系统上,access()检查真实的UID和真实的GID,而不是有效的UID和有效的GID.这只对setuid或setgid程序很重要,但它会引起强烈反响,因为它可能会给出"错误"的答案.
access()存在一些陷阱.在使用access()和之后做的其他事情之间有一个TOCTOU(检查时间,使用时间)窗口.[...未完待续...]
大多数时候,是的(可以使用`access()`检查文件是否存在),但在SUID或SGID程序中,即使这可能是不正确的.如果测试文件位于真实UID或真实GID无法访问的目录中,则`access()`可能会在存在时报告此类文件.深奥而且不太可能?是.
当我在代码中查找`access()`的原因时,我遇到了这个问题.我从DevC++转移到CodeBlocks,它停止工作.所以,这不是绝对可靠的; 给@Leffler +1个.
@JonathanLeffler虽然你的评论是真的,但是access()应该可以检查文件的*exists*(`F_OK`).
让我挑剔:) access()不是标准功能.如果要从更广泛的意义上采取"跨平台",这可能会失败:)
它对我不起作用,无论文件是否存在,它都返回-1
@AlexejMagura:这取决于您要检查的条件。在某种程度上,它还取决于您是否需要担心ACL(访问控制列表)还是“扩展属性”,这两者之一或两者都会影响您是否可以真正访问文件。最终,这是[LBYL(请先检查一下)](http://stackoverflow.com/questions/404795/)测试,但是检查是否允许对文件执行操作的可靠方法是EAFP(寻求宽恕比获得许可更容易)-也就是说,您应该尝试所需的访问并检查返回状态。_[…继续…]_

2> codebunny..:

像这样使用stat:

bool file_exist (char *filename)
{
  struct stat   buffer;   
  return (stat (filename, &buffer) == 0);
}

并称之为:

if (file_exist ("myfile.txt"))
{
  printf ("It exists\n");
}


您是否可以指出2 GB后失败的文档?此外,在这种情况下,替代方案是什么?
`stat()`和`access()`都受到TOCTOU漏洞的影响(`lstat()`也是如此,但`fstat()`是安全的).这取决于你要根据文件的存在与否做什么.使用正确的选项`open()`通常是处理问题的最佳方法,但是制定正确的选项可能很棘手.另请参阅关于EAFP的讨论(更容易请求宽恕而不是许可)和LBYL(在您跳跃之前看看) - 参见[LBYL vs EAFP in Java](http://stackoverflow.com/questions/404795/lbyl-vs-eafp -in-java /),例如.
@LudvigANorin:在这样的系统上,`access()`也有可能存在问题,并且有一些选项可用于使`access()`和`stat()`与大文件(大于2 GB)一起工作.
这不适用于所有系统上大于2GB的文件。

3> Dan Lenski..:

通常,当您想要检查文件是否存在时,这是因为您希望创建该文件(如果不存在).Graeme Perrow的答案很好,如果您不想创建该文件,但如果您这样做,它很容易受到竞争条件的影响:另一个进程可以在您检查文件是否存在之间创建文件,并且实际打开它以写入文件.(不要笑...... 如果创建的文件是符号链接,这可能会带来严重的安全隐患!)

如果你想检查是否存在创建文件(如果它不存在),原子级以便没有竞争条件,那么使用:

#include 
#include 

fd = open(pathname, O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR);
if (fd < 0) {
  /* failure */
  if (errno == EEXIST) {
    /* the file already existed */
    ...
  }
} else {
  /* now you can use the file */
}


如果要使用O_CREAT,则需要提供模式(权限)作为open()的第三个参数.还要考虑是否应该使用O_TRUNC或O_EXCL或O_APPEND.
Jonathan Leffler是对的,这个例子要求O_EXCL按照书面形式工作.
此外,您需要将模式指定为第三个参数:open(lock,O_CREAT | O_WRONLY | O_EXCL,S_IRUSR | S_IWUSR)
应该注意的是,这只是安全的,因为文件系统符合POSIX标准; 特别是,旧版本的NFS具有O_EXCL应该避免的竞争条件!有一个解决方法,记录在`open(2)`(在Linux上;你的操作系统的手册页可能有所不同),但它相当丑陋,可能无法抵御恶意攻击者.

4> Mecki..:

是.使用stat().见链接.

如果文件不存在,Stat将失败,否则很可能成功.如果它确实存在,但您对它所在的目录没有读取权限,它也将失败,但在这种情况下,任何方法都将失败(如何根据访问权限检查您可能看不到的目录内容?简单地说,你不能).

哦,正如其他人提到的,你也可以使用access().但是我更喜欢stat(),就好像文件存在一样,它会立即为我提供大量有用的信息(上次更新时间,有多大,拥有该文件的所有者和/或组,访问权限等) .


如果您只需要知道文件是否存在,那么访问是优先的.如果您不需要所有额外信息,Stat()可能会被大量听到.
实际上,当我使用ls-command列出目录时,它会为每个存在的文件调用stat,并且运行ls有很大的开销对我来说很新.实际上,您可以在包含数千个文件的目录上运行ls,并在几分之一秒内返回.
@Mecki:与支持硬链接的系统上的访问相比,stat具有非零的额外开销.这是因为访问只需要查看目录条目,而stat也必须查找inode.在具有不良搜索时间的存储设备(例如磁带)上,差异可能很大,因为目录条目和inode不太可能彼此相邻.
@Kevin除非仅将F_OK传递给它,否则access()会检查文件的文件访问权限,并且这些权限存储在该文件的索引节点中,而不是在其目录条目中(至少对于具有索引节点结构)。所以`access()`必须以与`stat()`访问inode完全相同的方式来访问inode。**因此,您所说的内容只有在不检查任何权限的情况下才成立!**实际上,在某些系统上,甚至在stat()之上实现了access()(例如,GNU Hurd上的glibc做到了)这样),因此一开始就无法保证。

5> mesutpiskin..:
FILE *file;
    if((file = fopen("sample.txt","r"))!=NULL)
        {
            // file exists
            fclose(file);
        }
    else
        {
            //File not found, no memory leak since 'file' == NULL
            //fclose(file) would cause an error
        }


`fopen()`是标准的C,它不会去任何地方.它只是被微软"弃用"了.除非您需要特定于平台的非可移植代码,否则不要使用`fopen_s()`.

6> SmacL..:

从Visual C++的帮助,我倾向于使用

/* ACCESS.C: This example uses _access to check the
 * file named "ACCESS.C" to see if it exists and if
 * writing is allowed.
 */

#include  
#include  
#include  

void main( void )
{
   /* Check for existence */
   if( (_access( "ACCESS.C", 0 )) != -1 )
   {
      printf( "File ACCESS.C exists\n" );
      /* Check for write permission */
      if( (_access( "ACCESS.C", 2 )) != -1 )
         printf( "File ACCESS.C has write permission\n" );
   }
}

还值得注意_accesss的模式值(const char*path,int mode)

00仅存在

02写权限

04阅读权限

06读写权限

因为你的fopen可能会在文件存在但无法按要求打开的情况下失败.

编辑:请阅读Mecki的帖子. stat()确实看起来像一个更简洁的方式.哼哼.

推荐阅读
谢谢巷议
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有