
FAQ CConsultez toutes les FAQ
Nombre d'auteurs : 28, nombre de questions : 175, création le 11 janvier 2013
Sommaire→Les entrées/sorties→Les fichiers et les dossiersLa solution la plus simple pour vérifier si un fichier existe c'est d'essayer de l'ouvrir.
FILE * fp = fopen("fichier.txt", "rb");
if (fp == NULL)
{
/* L'ouverture du fichier "fichier.txt" a echoue => le fichier "fichier.txt" n'existe pas. */
}
else
{
/* Le fichier a pu etre ouvert => le fichier existe. */
fclose(fp);
}
Cependant, cette technique n'est pas à 100% sûre car si le fichier a pu être ouvert, c'est en effet qu'il existe. Mais s'il n'a pas pu être ouvert, ça ne signifie pas forcément que le fichier n'existe pas (plusieurs raisons peuvent amener la demande d'ouverture d'un fichier à l'échec : le fichier n'existe pas, le système ne dispose pas d'assez de mémoire pour effectuer l'opération, vous n'avez pas le droit d'ouvrir le fichier, etc.). Il n'existe malheureusement pas de méthode standard qui permette de connaître la cause de l'échec de l'ouverture du fichier. Sous DOS/Windows et les systèmes de type UNIX, on peut tester si errno est égal à ENOENT (No entry (no such file or directory)).
Cette petite fonction permet de calculer très simplement la taille d'un fichier.
#include <stdio.h>
int fsize(const char * fname, long * ptr)
{
/* Cette fonction retourne 0 en cas de succes, une valeur differente dans le cas contraire. */
/* La taille du fichier, si elle a pu etre calculee, est retournee dans *ptr */
FILE * f;
int ret = 0;
f = fopen(fname, "rb");
if (f != NULL)
{
fseek(f, 0, SEEK_END); /* aller a la fin du fichier */
*ptr = ftell(f); /* lire l'offset de la position courante par rapport au debut du fichier */
fclose(f);
}
else
ret = 1;
return ret;
}
Le problème c'est que sous Windows par exemple, la taille d'un fichier peut dépasser la plus grande valeur positive représentable par le type long. La fonction GetFileAttributesEx permet de connaître entre autres la taille d'un fichier sans limitation comme dans le cas précédent. Rappelons que sur Win32, la taille du type unsigned int est de 4 octets (32 bits) ce qui signifie que la valeur maximale représentable par ce type est 2 ^ 32 - 1. GetFileAttributesEx retourne la taille du fichier sur une valeur de 64 bits ce qui assez grand pour représenter la taille de n'importe quel fichier manipulable sous Windows. En fait, il s'agit de deux valeurs de 32 bits : la partie haute, qui vaut 0 si la taille du fichier est inférieure à 2 ^ 32 octets soit 4 Go et la partie basse, les premiers 32 bits.
#include <windows.h>
int FileSize(const char * FileName, unsigned int * ptr)
{
/* Cette fonction retourne 0 en cas de succes, une valeur differente dans le cas contraire. */
/* La taille du fichier, si elle a pu etre calculee, est retournee dans *ptr */
WIN32_FILE_ATTRIBUTE_DATA attr;
int ret = 0;
if (GetFileAttributesEx(FileName, GetFileExInfoStandard, &attr))
{
/* La taille du fichier (entre autres) a pu etre lue */
if (attr.nFileSizeHigh == 0)
{
/* Le fichier fait moins de 4 Go */
*ptr = attr.nFileSizeLow;
}
else
ret = 2;
}
else
ret = 1;
return ret;
}
Il n'existe pas en C de fonction réalisant la copie d'un fichier. Il est donc nécessaire de créer une fonction lisant le fichier pour le copier dans le fichier de destination.
#include <stdio.h>
int copier_fichier(char const * const source, char const * const destination)
{
FILE* fSrc;
FILE* fDest;
char buffer[512];
int NbLus;
if ((fSrc = fopen(source, "rb")) == NULL)
{
return 1;
}
if ((fDest = fopen(destination, "wb")) == NULL)
{
fclose(fSrc);
return 2;
}
while ((NbLus = fread(buffer, 1, 512, fSrc)) != 0)
fwrite(buffer, 1, NbLus, fDest);
fclose(fDest);
fclose(fSrc);
return 0;
}
Remarque : il est aisé de modifier cette fonction afin de concaténer le fichier source avec le fichier destination en ouvrant ce
fichier en mode ajout ("ab").
Sous Windows, il y a la fonction CopyFile qui permet de ne pas avoir à coder sa propre fonction.
BOOL CopyFile( LPCTSTR lpExistingFileName, /* Nom du fichier source */
LPCTSTR lpNewFileName, /* Nom du fichier destination */
BOOL bFailIfExists /* Si != 0, la copie sera annulée si le fichier existe déjà */
);
Le langage C ne fournit pas de fonction pour supprimer une ligne dans un fichier, il faut obligatoirement lire le fichier et de recopier chaque ligne hormis celles que nous désirons supprimer. Voici un exemple de programme supprimant les lignes commencant par # dans un fichier (afin de ne pas surcharger inutilement le code de l'exemple, nous supposons qu'aucune ligne ne fait plus de 256 caractères).
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char ligne[256];
FILE * fIn;
FILE * fOut;
if ((fIn = fopen("texte.txt", "r")) == NULL)
return EXIT_FAILURE;
if ((fOut = fopen("texte.tmp", "w")) == NULL)
{
fclose(fIn);
return EXIT_FAILURE;
}
while (fgets(ligne, sizeof ligne, fIn))
{
if (ligne[0] != '#')
fputs(ligne, fOut);
}
fclose(fIn);
fclose(fOut);
rename("texte.tmp", "texte.txt");
return 0;
}
Le principe est le même pour supprimer un enregistrement d'un fichier binaire.
Sous Windows, à l'aide de DeleteFile (inclure windows.h) et sous UNIX (et plus généralement n'importe quel système se conformant à la norme POSIX), à l'aide de la fonction unlink (déclarée dans unistd.h). La bibliothèque standard du C fournit également une fonction qui sait remplir cette tâche qui n'est autre que remove (déclarée dans stdio.h).
#include <stdio.h>
int remove(const char * pathname);
Sous Windows, on utilise les fonction FindFirstFile() et FindNextFile() en recherchant les fichiers nommés "*.*" (c'est-à-dire tous les fichiers, tous les dossiers). Le HANDLE retourné par FindFirstFile() doit être fermé dès qu'il n'est plus nécessaire grâce à la fonction FindClose(). Ces fonctions ne parcourent pas les sous dossiers. Le programme suivant liste le contenu du répertoire courant.
#include <stdio.h>
#include <windows.h>
int main(void)
{
WIN32_FIND_DATA File;
HANDLE hSearch;
hSearch = FindFirstFile("*.*", &File);
if (hSearch != INVALID_HANDLE_VALUE)
{
do {
printf("%s\n", File.cFileName);
} while (FindNextFile(hSearch, &File));
FindClose(hSearch);
}
return 0;
}
Dans un environnement conforme à la norme POSIX, on utilisera plutôt opendir, readdir puis closedir.
#include <stdio.h>
#include <dirent.h>
int main(void)
{
DIR * rep = opendir(".");
if (rep != NULL)
{
struct dirent * ent;
while ((ent = readdir(rep)) != NULL)
{
printf("%s\n", ent->d_name);
}
closedir(rep);
}
return 0;
}
libzip permet de lire, de créer et de modifier les archives zip. L'extrait de code suivant ajoute un fichier dans une archive, l'archive sera créée si elle n'existe pas encore.
int visu;
struct zip * f_zip=NULL;
struct zip_source * n_zip=NULL;
f_zip=zip_open("feuille.zip",ZIP_CREATE,NULL);
n_zip=zip_source_file(f_zip,"content.xml",0,0); /* le nom de ce document est sans importance */
if ((visu=zip_name_locate(f_zip,"content.xml",ZIP_FL_NOCASE)==-1) /* recherche de l'emplacement du fichier content.xml dans le zip */
{ /* nouveau document dans le fichier zip : le fichier content.xml n'y est pas */
zip_add(f_zip,"content.xml",n_zip); /* c'est là qu'on fixe le nom qu'aura le nouveau document dans le fichier zip */
}
else
{ /* modification d'un document dans le fichier zip : content.xml est déjà dedans */
zip_replace(f_zip,visu,n_zip); /* notre document remplace le document qui ce trouve à l'emplacement visu */
} /* et récupère le nom de l'ancien document */
zip_close(f_zip);
Lien : libzip



