What's the best way to check if a file exists in C?

Есть ли лучший способ, чем просто попытаться открыть файл?

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

8 ответов

Решение

Посмотрите вверх 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 (успех), потому что файл не имеет установленного атрибута только для чтения, но у вас все еще может не быть разрешения на запись в файл.

Используйте stat следующим образом:

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

и назовите это так:

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

Обычно, когда вы хотите проверить, существует ли файл, это потому, что вы хотите создать этот файл, если он не существует. Ответ Грэма Перроу хорош, если вы не хотите создавать этот файл, но он уязвим для состояния гонки, если вы это сделаете: другой процесс может создать файл между вами, проверив, существует ли он, и вы фактически открываете его для записи в него, (Не смейтесь... это может иметь плохие последствия для безопасности, если созданный файл был символической ссылкой!)

Если вы хотите проверить существование и создать файл, если он не существует, атомарно, чтобы не было условий гонки, используйте это:

#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 */
}

Да. Используйте stat(). Смотрите ссылку.

Stat не удастся, если файл не существует, в противном случае, скорее всего, успешно. Если он существует, но у вас нет доступа на чтение к каталогу, в котором он существует, он также потерпит неудачу, но в этом случае произойдет сбой любого метода (как вы можете проверить содержимое каталога, который вы можете не видеть в соответствии с правами доступа? Просто не можешь)

О, как уже упоминалось, вы также можете использовать access(). Однако я предпочитаю stat(), так как если файл существует, он сразу же даст мне много полезной информации (когда он последний раз обновлялся, насколько он большой, владелец и / или группа, которой принадлежит файл, права доступа и т. Д.),

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
        }

Я думаю, что функция доступа (), которая находится в unistd.h хороший выбор для 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

Вы можете использовать функцию realpath().

resolved_file = realpath(file_path, NULL);
if (!resolved_keyfile) {
   /*File dosn't exists*/
   perror(keyfile);
   return -1;
}

Из справки 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" );
   }
}

Также стоит отметить значения режима _accesss (const char * path,int mode)

00 Только существование

02 Разрешение на запись

04 Разрешение на чтение

06 Разрешение на чтение и запись

Поскольку ваш fopen может не работать в ситуациях, когда файл существует, но не может быть открыт в соответствии с запросом.

Изменить: Просто прочитайте пост Меки. stat () выглядит как аккуратный путь. Хо гул.

Я не могу вспомнить, откуда я взял это из того, что я использовал в своем задании (я обычно копирую и вставляю URL, где я нашел его, как простую форму цитирования), и я не могу расшифровать, что за (file) = 0 Хотя я предполагаю, что установка любых ссылок на файл в 0 является избыточностью.

#define fclose(file)  ((file) ? fclose(file) : 0, (file) = 0)

file если указатель объявлен как:

FILE *file=NULL;

Для Windows проверьте следующую функцию: HANDLE FindFirstFile(...);

Другие вопросы по тегам