除了简单地尝试打开文件,有更好的方法吗?
int exists(const char *fname)
{
FILE *file;
if ((file = fopen(fname, "r")))
{
fclose(file);
return 1;
}
return 0;
}
除了简单地尝试打开文件,有更好的方法吗?
int exists(const char *fname)
{
FILE *file;
if ((file = fopen(fname, "r")))
{
fclose(file);
return 1;
}
return 0;
}
查找位于unistd.h
中的access()
函数。您可以使用该函数替换您的函数。
if (access(fname, F_OK) == 0) {
// file exists
} else {
// file doesn't exist
}
unistd.h
不存在。为了让它工作,需要定义:#ifdef WIN32
#include <io.h>
#define F_OK 0
#define access _access
#endif
R_OK
、W_OK
和X_OK
来代替F_OK
,检查读取权限、写入权限和执行权限(分别),而不是仅存在性,并且您可以将它们中的任何一个进行OR运算(即使用R_OK|W_OK
检查读取和写入权限)。W_OK
可靠地测试写入权限,因为访问函数不考虑DACL。access(fname, W_OK)
可能会返回0(成功),因为文件没有设置只读属性,但您仍然可能没有权限写入该文件。access()
来检查文件是否存在是可以的,但在SUID或SGID程序中,即使这样做也可能是不正确的。如果测试的文件位于真实UID或真实GID无法访问的目录中,则access()
可能会报告该文件不存在,尽管它实际上存在。这听起来很抽象、不太可能发生?是的。 - Jonathan Leffler像这样使用stat
:
#include <sys/stat.h> // stat
#include <stdbool.h> // bool type
bool file_exists (char *filename) {
struct stat buffer;
return (stat (filename, &buffer) == 0);
}
并这样进行调用:
#include <stdio.h> // printf
int main(int ac, char **av) {
if (ac != 2)
return 1;
if (file_exists(av[1]))
printf("%s exists\n", av[1]);
else
printf("%s does not exist\n", av[1]);
return 0;
}
access()
也可能存在问题,但有一些选项可以使用,使 access()
和 stat()
能够处理大于2GB的文件。 - Jonathan Lefflerstat
是否不像access
一样容易受到TOCTOU漏洞的影响?(我不确定这是否更好。) - Telemachusstat()
和access()
均存在TOCTOU漏洞(lstat()
也有,但fstat()
是安全的)。根据文件的存在与否来确定接下来要做什么。通常使用正确的open()
选项处理问题是最好的方法,但制定正确选项可能有些棘手。同时可以参考EAFP(“容易请求宽恕,而不是事先获准”)和LBYL(“先看后跳”)的讨论,例如查看Java中LBYL vs EAFP。 - Jonathan Leffleropen()
函数以TOC方式打开文件(此时open()
的返回值就是检查文件是否存在的依据),然后将此描述符用于TOU操作。这样即使在TOU操作期间文件不存在,您仍然可以通过文件描述符访问它。只要有进程打开文件,其内容就会被保留。 - Hi-Angel通常当您想要检查文件是否存在时,这是因为您想要在文件不存在时创建该文件。如果您不想创建该文件,则Graeme Perrow的回答 很好,但是如果您想创建该文件,则会存在竞争条件:另一个进程可能会在您检查文件是否存在之间创建该文件,并实际上打开它进行写操作。(别笑...如果创建的文件是符号链接,则可能具有严重的安全影响!)
如果您想要检查文件是否存在并在文件不存在时创建该文件,原子地,以避免竞争条件,则使用此代码:
#include <fcntl.h>
#include <errno.h>
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 */
}
open(2)
文档中有记录(适用于Linux系统;其他操作系统的手册可能会有所不同),但它相当丑陋,并且可能无法抵御恶意攻击者。 - Kevin是的,使用 stat()
。参见stat(2)
的man页面。
stat()
会在文件不存在时失败,否则大多数情况下都会成功。如果文件存在,但您无法读取它所在的目录,则也会失败,但在这种情况下,任何方法都将失败(根据访问权限,您如何检查可能看不到的目录的内容?简单地说,您不能)。
哦,正如其他人提到的,您还可以使用access()
。然而,我更喜欢使用stat()
,因为如果文件存在,它将立即为我提供大量有用的信息(最后一次更新时间、大小、拥有者和/或组,访问权限等等)。
access()
函数,否则该函数会检查文件的访问权限。这些权限存储在该文件对应的 inode 中,并不在其目录项中(至少对于所有具有类似 inode 结构的文件系统是如此)。因此,access()
函数必须像 stat()
一样精确地访问 inode。所以,如果你没有检查任何权限,你所说的话就不成立了!实际上,某些系统上的 access()
函数甚至是基于 stat()
实现的(例如,在 GNU Hurd 上的 glibc 就是这样实现的),因此首先就不存在保证。 - MeckiFILE *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 函数,它不会消失。只有 Microsoft 将其标记为“已弃用”。如果你不想编写平台特定、不可移植的代码,请勿使用 fopen_s()
。 - Andrew Henle(file = fopen("sample.txt","r"))!=NULL
。 - user16217248unistd.h
中的access()函数是Linux
上的不错选择(你也可以使用stat)。您可以按照以下方式使用它:#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
void fileCheck(const char *fileName);
int main (void) {
char *fileName = "/etc/sudoers";
fileCheck(fileName);
return 0;
}
void fileCheck(const char *fileName){
if(!access(fileName, F_OK )){
printf("The File %s\t was Found\n",fileName);
}else{
printf("The File %s\t not Found\n",fileName);
}
if(!access(fileName, R_OK )){
printf("The File %s\t can be read\n",fileName);
}else{
printf("The File %s\t cannot be read\n",fileName);
}
if(!access( fileName, W_OK )){
printf("The File %s\t it can be Edited\n",fileName);
}else{
printf("The File %s\t it cannot be Edited\n",fileName);
}
if(!access( fileName, X_OK )){
printf("The File %s\t is an Executable\n",fileName);
}else{
printf("The File %s\t is not an Executable\n",fileName);
}
}
您将获得以下输出:
The File /etc/sudoers was Found
The File /etc/sudoers cannot be read
The File /etc/sudoers it cannot be Edited
The File /etc/sudoers is not an Executable
resolved_file = realpath(file_path, NULL);
if (!resolved_keyfile) {
/*File dosn't exists*/
perror(keyfile);
return -1;
}
NULL
,那么realpath()
函数将使用malloc
分配缓冲区,调用者应该使用free
释放该缓冲区。 - Peter Holzerrealpath()
还会将 errno
设置为 ENOENT
,以指示所命名的文件实际上不存在。 - Peter Holzer从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 <io.h>
#include <stdio.h>
#include <stdlib.h>
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" );
}
}
_access(const char *path, int mode)
的模式值:
00:仅存在
02:写权限
04:读权限
06:读和写权限
fopen
在文件存在但无法按请求打开的情况下可能会失败。stat()
看起来更加整洁。哎呀。void main
? - user16217248main()
签名,它们都返回int
。如果编译器/环境支持void main()
,那么它只是作为非官方扩展支持。 - HunterZvoid main()
是否会涉及到标准中的未定义行为? - user16217248
fopen()
/fclose()
方法的一个问题在于,尽管文件存在,您可能无法打开它以进行读取。例如,/dev/kmem
存在,但大多数进程即使要进行读取也无法打开它。/etc/shadow
是另一个这样的文件。当然,stat()
和access()
都依赖于能够访问包含文件的目录;如果您无法执行此操作(在包含文件的目录上没有执行权限),那么所有都是不确定的。 - Jonathan Lefflerif (file = fopen(fname, "r"))
will give a warning. Use parenthesis around statement inside the if-statementif ((file = fopen(fname, "r")))
- Joakim(())
只是在解决症状,而不是问题。 将其分成两行; 多一行也不会有太大的影响。file = fopen(fname, "r");
如果(file) - alx - recommends codidact