Будет ли errno == ENOENT достаточной проверкой, чтобы проверить, существует ли файл в C?

Использование PellesC в Windows 8.1.

Я знаю, что эта тема обсуждалась много раз с множеством решений. Я читал решения, в которых говорится об использовании CreateFile, PathFileExists, GetFileAttributes, _access, которые я немного понимаю.

Я также прочитал важный момент об условиях гонки в ответах на вопросы Самый быстрый способ проверить, существует ли файл и Как лучше всего проверить, существует ли файл в C? (кроссплатформенный).

Итак, если я открою файл, используя fopen() в C, и когда он выйдет из строя (по какой-либо причине) и передаст NULL обратно; тогда я могу дополнительно проверить errno == ENOENT и довольствоваться этим и правильно сообщить, что файл не существует.

#include <stdio.h>
#include <string.h>
#include <errno.h>

int file_exists(char filename[]) {
    int err = 0; //copy of errno at specific instance
    int r = 0;   //1 for exists and 0 for not exists
    FILE *f = NULL;

    //validate
    if (filename == NULL) {
        puts("Error: bad filename.");
        return 0;
    }

    printf("Checking if file %s exists...\n", filename);

    //check
    errno = 0;
    f = fopen(filename, "r");
    err = errno;
    if (f == NULL) {
        switch (errno) {
          case ENOENT:
            r = 0;
            break;
          default:
            r = 1;
        }
        printf("errno = %d\n%s\n", err, strerror(err));
    } else {
        fclose(f);
        r = 1;
    }

    if (r == 0) {
        puts("It does not.");
    } else {
        puts("It does.");
    }

    return r;
}

person Jazz    schedule 05.09.2018    source источник
comment
Если вы хотите сообщить пользователю о причине ошибки, то использование errno действительно то, что вам нужно. Если вы хотите узнать, существует ли файл, то отсутствие ENOENT не гарантирует этого (вы могли получить другую ошибку, например, EPERM, или файл мог быть создан как часть fopen позвонить или ...). Можете ли вы описать немного подробнее, чего вы пытаетесь достичь?   -  person Sander De Dycker    schedule 05.09.2018
comment
Вышлю код. подождите минуту.   -  person Jazz    schedule 05.09.2018


Ответы (1)


fopen нужно сделать много вещей и проверить, прежде чем файл будет открыт. ENOENT означает, что файл не существует, но файл не существует не подразумевает ENOENT.

Возможно, что файл не существует, и вы получите другую ошибку, например, EACCES из-за невозможности прочитать родительский каталог.


С другой стороны, ENOENT из fopen не означает, что какой-то другой процесс не мог создать файл даже до того, как fopen завершит работу, или до того, как вы проверите errno и так далее; именно по этой причине C11 добавил флаг x для открытия файла для записи в эксклюзивном режиме — ошибка, если файл уже существует.


Подводя итог: если вы получили ENOENT, файл не существовал, когда вы пытались его открыть. Если вы получите какую-то другую ошибку, то каждый другой код ошибки будет принадлежать к одному из этих 3-х классов - это наверняка, что либо

  • файл существовал или
  • оно не могло существовать
  • или он мог существовать в то время

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

person Antti Haapala    schedule 05.09.2018