web-dev-qa-db-fra.com

Quel est le meilleur moyen de vérifier si un fichier existe en C?

Existe-t-il un meilleur moyen que d'essayer simplement d'ouvrir le fichier?

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

Recherchez la fonction access() qui se trouve dans unistd.h. Vous pouvez remplacer votre fonction par

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

Vous pouvez également utiliser R_OK, W_OK et X_OK à la place de F_OK pour vérifier les droits de lecture, d'écriture et d'exécution (respectivement) plutôt que d'existence, et vous pouvez OR tous les deux ensemble (c.-à-d. vérifier les droits de lecture et permission d'écriture en utilisant R_OK|W_OK)

Mise à jour: Notez que sous Windows, vous ne pouvez pas utiliser W_OK pour tester de manière fiable le droit d’écriture, car la fonction d’accès ne prend pas en compte les DACL. access( fname, W_OK ) peut renvoyer 0 (succès) car l'attribut en lecture seule n'est pas défini dans le fichier, mais vous n'êtes peut-être toujours pas autorisé à l'écrire dans le fichier.

528
Graeme Perrow

Utilisez stat comme ceci:

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

et appelez comme ça:

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

Généralement, lorsque vous voulez vérifier si un fichier existe, c'est parce que vous voulez créer ce fichier s'il n'en a pas. La réponse de Graeme Perrow est bonne si vous ne pas voulez créer ce fichier, mais si vous le rencontrez, il est vulnérable à la concurrence. Un autre processus peut créer le fichier entre vous en vérifiant s'il existe, et en fait l'ouvrir pour y écrire. (Ne riez pas ... cela pourrait avoir mauvais implications pour la sécurité si le fichier créé était un lien symbolique!)

Si vous voulez vérifier l'existence et créer le fichier s'il n'existe pas, atomiquement afin qu'il n'y ait pas de race conditions, alors utilisez ceci:

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

Oui. Utilisez stat(). Voir la page de manuel de stat(2) .

stat() échouera si le fichier n'existe pas, sinon la plupart du temps réussiront. S'il existe, mais que vous n'avez pas d'accès en lecture au répertoire dans lequel il existe, il échouera également, mais dans ce cas, toute méthode échouera (comment inspecter le contenu d'un répertoire que vous ne pouvez pas voir en fonction des droits d'accès?). Simplement, vous ne pouvez pas).

Oh, comme quelqu'un d'autre l'a mentionné, vous pouvez également utiliser access(). Cependant, je préfère stat(), car si le fichier existe, il me fournira immédiatement de nombreuses informations utiles (date de sa dernière mise à jour, taille, propriétaire et/ou groupe propriétaire du fichier, autorisations d'accès, etc.).

29
Mecki
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
        }
9
mesutpiskin

De l'aide Visual C++, j'aurais tendance à aller avec

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

Il convient également de noter les valeurs de mode de __access(const char *path,_int mode _)_:

  • 00: Existence seulement

  • 02: permission d'écriture

  • 04: autorisation de lecture

  • 06: autorisation de lecture et d'écriture

En tant que votre fopen pourrait échouer dans des situations où le fichier existait mais ne pourrait pas être ouvert comme demandé.

Edit: Il suffit de lire le post de Mecki. stat() ressemble à une façon plus ordonnée d'aller. Ho hum.

6
SmacL

Je pense que la fonction access () , qui se trouve dans unistd.h est un bon choix pour Linux (vous pouvez aussi utiliser stat ).

Vous pouvez l'utiliser comme ça:

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

Et vous obtenez la sortie suivante:

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
3
Michi

Vous pouvez utiliser la fonction realpath ().

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