Jak najlepiej sprawdzić, czy plik istnieje w C?

Czy jest lepszy sposób niż po prostu próba otwarcia pliku?

int exists(const char *fname)
{
    FILE *file;
    if ((file = fopen(fname, "r")))
    {
        fclose(file);
        return 1;
    }
    return 0;
}
Author: jww, 2008-10-23

9 answers

Wyszukaj access() funkcję znajdującą się w unistd.h. Możesz zastąpić swoją funkcję

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

Możesz również użyć R_OK, W_OK, i X_OK zamiast F_OK, aby sprawdzić uprawnienia do odczytu, uprawnienia do zapisu i uprawnienia do wykonywania (odpowiednio) zamiast istnienia, i możesz lub dowolna z nich razem (tj. sprawdź zarówno uprawnienia do odczytu , jak i} używając R_OK|W_OK)

Update : zauważ, że w systemie Windows nie możesz używać W_OK do niezawodnego testowania uprawnień do zapisu, ponieważ Funkcja dostępu nie uwzględnia DACL. access( fname, W_OK ) może zwrócić 0 (sukces), ponieważ plik nie ma ustawionego atrybutu Tylko do odczytu, ale nadal możesz nie mieć uprawnień do zapisu do pliku.

 647
Author: Graeme Perrow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-03 11:06:46

Użyj stat w ten sposób:

#include <sys/stat.h>   // stat
#include <stdbool.h>    // bool type

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

I nazwij to tak:

#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;
}
 124
Author: codebunny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-19 16:59:12

Zazwyczaj, gdy chcesz sprawdzić, czy plik istnieje, to dlatego, że chcesz utworzyć ten plik, jeśli nie. Graeme Perrow odpowiedź jest dobra, jeśli nie chcesz utworzyć tego pliku, ale jest podatny na warunki wyścigu, jeśli to zrobisz: inny proces może utworzyć plik pomiędzy Tobą, sprawdzając, czy istnieje, a ty faktycznie otwierasz go, aby do niego napisać. (Nie śmiej się... może to mieć złe implikacje dla bezpieczeństwa, jeśli utworzony plik był / align = "left" / )

Jeśli chcesz sprawdzić istnienie i Utwórz plik, jeśli nie istnieje, atomicznie , aby nie było warunków rasowych, użyj tego:

#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 */
}
 93
Author: Dan Lenski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-29 03:56:48

Tak. Użyj stat(). Zobacz stronę man dlastat(2).

stat() nie powiedzie się, jeśli plik nie istnieje, w przeciwnym razie najprawdopodobniej się powiedzie. Jeśli istnieje, ale nie masz dostępu do odczytu do katalogu, w którym istnieje, również się nie powiedzie, ale w takim przypadku każda metoda zawiedzie (jak możesz sprawdzić zawartość katalogu, którego możesz nie zobaczyć zgodnie z prawami dostępu? Po prostu nie możesz).

Oh, jak ktoś inny wspomniał, możesz również użyć access(). Jednak wolę stat(), jakby plik istnieje to natychmiast uzyskać mi wiele przydatnych informacji (kiedy był ostatnio aktualizowany, jak duży jest to, właściciel i / lub grupa, która jest właścicielem pliku, uprawnienia dostępu, i tak dalej).

 32
Author: Mecki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-05 16:32:46
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
        }
 16
Author: mesutpiskin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-23 06:25:13

Możesz użyć funkcji realpath ().

resolved_file = realpath(file_path, NULL);
if (!resolved_keyfile) {
   /*File dosn't exists*/
   perror(keyfile);
   return -1;
}
 6
Author: bharath reddy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-08 06:14:20

Z Visual C++ help, zwykle wybieram

/* 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" );
   }
}

Warto również zwrócić uwagę na wartości trybu_access(const char *path,int mode):

  • 00: tylko istnienie

  • 02: uprawnienia zapisu

  • 04: uprawnienia do odczytu

  • 06: uprawnienia do odczytu i zapisu

Ponieważ twój fopen może zawieść w sytuacjach, w których plik istniał, ale nie można go otworzyć zgodnie z żądaniem.

Edit: wystarczy przeczytać post Meckiego. stat() wygląda jak porządniejszy sposób. Ho hum.

 6
Author: SmacL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-05 15:34:02

Myślę, że access () funkcja, która znajduje się w unistd.h jest dobrym wyborem dla Linux (Możesz również użyć stat).

Możesz go użyć tak:

#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);
    }
}

I otrzymujesz następujące wyjście:

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
 4
Author: Michi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-26 15:45:17

Nie pamiętam skąd mam to, że użyłem w moim zadaniu (Zwykle kopiuję wklejać adres URL, gdzie znalazłem to jako łatwą formę cytowania) i nie mogę rozszyfrować, co końcowe (file) = 0 jest, chociaż moje najlepsze przypuszczenie jest redundancja, aby ustawić wszelkie odniesienia do pliku na 0.

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

file Jeśli wskaźnik zadeklarowany jako:

FILE *file=NULL;
 0
Author: mLstudent33,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-19 02:43:44