1. Introduction▲
Pour utiliser les archives zip plusieurs bibliothèques sont disponibles. Dans ce tutoriel nous allons nous intéresser à la libzip. Cette bibliothèque est écrite en C et permet de lire, créer ou modifier les archives zip. À ce jour, la dernière version est la 0.10 qui date du 18/03/2010. C'est cette version qui a été utilisée pour ce tutoriel. Le manuel de la bibliothèque est très clair et quasiment toutes les fonctions sont détaillées. Il se trouve en ligne ou via man libzip pour la bibliothèque en général et man "nom de la commande".
Ce document présente comment :
- lister le contenu d'une archive zip ;
- effacer un fichier/dossier d'une archive zip ;
- renommer un fichier/dossier d'une archive zip ;
- remplacer un fichier d'une archive zip ;
- extraire un fichier/dossier d'une archive zip ;
- décompresser une archive zip ;
- créer une archive zip.
Tous les codes sont en C.
Les codes ci-dessous peuvent faire appel à des fonctions non présentes dans cette page mais le tout est disponible dans le code source C présent à la fin de la page. Le tutoriel n'est disponible que pour les systèmes UNIX/POSIX. Il ne devrait pas être difficile à adapter pour la plateforme Windows. Le code présente des appels particuliers POSIX et considère que les chemins sont de type UNIX '/' et non de type Windows '\'. Tout a été testé sur FreeBSD, si des modifications sont à apporter pour d'autres systèmes n'hésitez pas à me le faire savoir.
2. Exemple de Code▲
2-A. Lister le contenu d'une archive zip▲
2-A-1. Algorithme▲
Ouvrir l'archive (Fonction zip_open).
Compter le nombre d'éléments dans l'archive (Fonction zip_get_num_files).
Pour chaque élément, afficher son nom (Fonction zip_get_name).
Fermer l'archive (Fonction zip_close).
2-A-2. Code source▲
/**
*
\fn
static int afficherFichierZip(const char* fichierZip)
*
\brief
Affiche les fichiers à l'intérieur de l'archive Zip.
*
*
\return
ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
*/
static
int
afficherFichierZip
(
const
char
*
fichierZip)
{
if
(
fichierZip ==
NULL
)
return
ZIPZAP_FAILURE;
int
err =
0
;
struct
zip *
f_zip=
NULL
;
f_zip =
zip_open
(
fichierZip, ZIP_CHECKCONS, &
err); /* on ouvre l'archive zip */
/* s'il y a des erreurs */
if
(
err !=
ZIP_ER_OK)
{
zip_error_to_str
(
buf_erreur, sizeof
buf_erreur, err, errno);
printf
(
"
Error %d : %s
\n
"
,err, buf_erreur);
return
ZIPZAP_FAILURE;
}
/* si le fichier zip n'est pas ouvert */
if
(
f_zip==
NULL
)
{
printf
(
"
Erreur à l'ouverture du fichier %s
\n
"
, fichierZip);
return
ZIPZAP_FAILURE;
}
/* on récupère le nombre de fichiers dans l'archive zip */
int
count =
zip_get_num_files
(
f_zip);
if
(
count==-
1
)
{
printf
(
"
Erreur à la lecture du fichier %s
\n
"
, fichierZip);
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
int
i =
0
;
printf
(
"
Nombre de fichiers dans l'archive : %d
\n
"
,count);
for
(
i=
0
; i<
count; i++
)
{
/* on utilise la position "i" pour récupérer le nom des fichiers */
printf
(
"
%s
\n
"
, zip_get_name
(
f_zip, i, ZIP_FL_UNCHANGED));
}
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_SUCCESS;
}
2-B. Effacer un fichier/dossier d'une archive zip▲
2-B-1. Algorithme▲
Ouvrir l'archive (Fonction zip_open).
Rechercher le fichier/dossier dans l'archive (Fonction zip_name_locate).
Si c'est un dossier
pour chaque élément du dossier, le supprimer (Fonction zip_delete).
Sinon
le supprimer (Fonction zip_delete).
Fermer l'archive (Fonction zip_close).
2-B-2. Code source▲
/**
*
\fn
static int effacerFichierZip(const char* fichierZip, const char* fichier)
*
\brief
Efface le fichier/dossier "fichier" de l'archive zip "fichierZip".
*
*
\param
fichierZip Archive zip contenant le fichier à effacer.
*
\param
fichier Nom du fichier/dossier à effacer.
*
*
\return
ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
*/
static
int
effacerFichierZip
(
const
char
*
fichierZip, const
char
*
fichier)
{
int
visu =
0
;
struct
zip *
f_zip=
NULL
;
int
err =
0
;
f_zip=
zip_open
(
fichierZip,ZIP_CREATE,&
err);
/* s'il y a des erreurs */
if
(
err !=
ZIP_ER_OK)
{
zip_error_to_str
(
buf_erreur, sizeof
buf_erreur, err, errno);
printf
(
"
Error %d : %s
\n
"
,err, buf_erreur);
return
ZIPZAP_FAILURE;
}
/* si le fichier zip n'est pas ouvert */
if
(
f_zip==
NULL
)
{
printf
(
"
Erreur à l'ouverture du fichier %s
\n
"
, fichierZip);
return
ZIPZAP_FAILURE;
}
visu=
zip_name_locate
(
f_zip,fichier,0
);
if
(
visu==-
1
) /* recherche de l'emplacement du fichier dans le zip */
{
printf
(
"
Le fichier %s n'existe pas dans %s
\n
"
, fichier, fichierZip);
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
/* si on demande la suppression d'un répertoire */
if
(
fichier[strlen
(
fichier)-
1
]==
'
/
'
)
{
char
*
ptr =
NULL
;
int
i =
0
;
int
count =
zip_get_num_files
(
f_zip);
if
(
count==-
1
)
{
printf
(
"
Erreur à l'ouverture du fichier %s
\n
"
, fichierZip);
zip_close
(
f_zip);
f_zip =
NULL
;
ptr =
NULL
;
return
ZIPZAP_FAILURE;
}
for
(
i=
0
; i<
count; i++
)
{
/* on parcourt tous les fichiers du zip pour savoir si un fichier est dans le dossier à supprimer */
if
(
(
ptr=
strstr
(
zip_get_name
(
f_zip, i, ZIP_FL_UNCHANGED), fichier)) !=
NULL
)
{
/* on efface le fichier positionné à l'index i */
if
(
zip_delete
(
f_zip,i) ==
-
1
)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
zip_close
(
f_zip);
f_zip =
NULL
;
ptr =
NULL
;
return
ZIPZAP_FAILURE;
}
printf
(
"
Le fichier %s a été supprimé dans %s
\n
"
, zip_get_name
(
f_zip, i, ZIP_FL_UNCHANGED), fichierZip);
}
}
ptr =
NULL
;
}
else
{
/* sinon on supprime simplement le fichier trouvé par zip_name_locate à la position visu */
if
(
zip_delete
(
f_zip,visu) ==
-
1
)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
printf
(
"
Le fichier %s a été supprimé dans %s
\n
"
, fichier, fichierZip);
}
/* lecture terminée, fermeture de l'archive */
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_SUCCESS;
}
2-C. Renommer un fichier/dossier d'une archive zip▲
2-C-1. Algorithme▲
Ouvrir l'archive (Fonction zip_open).
Rechercher le fichier/dossier dans l'archive (Fonction zip_name_locate).
Si c'est un dossier
pour chaque élément du dossier, le renommer (Fonction zip_rename).
Sinon
le renommer (Fonction zip_rename).
Fermer l'archive (Fonction zip_close).
2-C-2. Code source▲
/**
*
\fn
static int renommerFichierZip(const char* fichierZip, const char* fichierFrom, const char* fichierTo)
*
\brief
Efface le fichier/dossier "fichierFrom" en "FichierTo" de l'archive zip "fichierZip".
*
*
\param
fichierZip Archive zip contenant le fichier à effacer.
*
\param
fichierFrom Nom du fichier/dossier en entrée.
*
\param
fichierTo Nom du fichier/dossier en sortie.
*
*
\return
ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
*/
static
int
renommerFichierZip
(
const
char
*
fichierZip, const
char
*
fichierFrom, const
char
*
fichierTo)
{
int
visu =
0
;
struct
zip *
f_zip=
NULL
;
int
err =
0
;
f_zip=
zip_open
(
fichierZip,ZIP_CREATE,&
err);
/* s'il y a des erreurs */
if
(
err !=
ZIP_ER_OK)
{
zip_error_to_str
(
buf_erreur, sizeof
buf_erreur, err, errno);
printf
(
"
Error %d : %s
\n
"
,err, buf_erreur);
return
ZIPZAP_FAILURE;
}
/* si le fichier zip n'est pas ouvert */
if
(
f_zip==
NULL
)
{
printf
(
"
Erreur à l'ouverture du fichier %s
\n
"
, fichierZip);
return
ZIPZAP_FAILURE;
}
/* recherche de l'emplacement du fichier dans le zip */
visu=
zip_name_locate
(
f_zip,fichierFrom,0
);
if
(
visu==-
1
)
{
printf
(
"
Le fichier %s n'existe pas dans %s
\n
"
, fichierFrom, fichierZip);
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
/* si on demande de renommer un répertoire */
if
(
fichierFrom[strlen
(
fichierFrom)-
1
]==
'
/
'
)
{
char
*
ptr =
NULL
;
int
i =
0
;
int
count =
zip_get_num_files
(
f_zip);
if
(
count==-
1
)
{
printf
(
"
Erreur à l'ouverture du fichier %s
\n
"
, fichierZip);
return
ZIPZAP_FAILURE;
}
for
(
i=
0
; i<
count; i++
)
{
/* on parcourt tous les fichiers du zip pour savoir si un fichier est dans le dossier à supprimer */
if
(
(
ptr=
strstr
(
zip_get_name
(
f_zip, i, ZIP_FL_UNCHANGED), fichierFrom)) !=
NULL
)
{
/* si c'est le répertoire on lui applique un traitement particulier */
if
(
strlen
(
fichierFrom)==
strlen
(
zip_get_name
(
f_zip, i, ZIP_FL_UNCHANGED)))
{
if
(
zip_rename
(
f_zip,i,fichierTo) ==
-
1
)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
zip_close
(
f_zip);
f_zip =
NULL
;
ptr =
NULL
;
return
ZIPZAP_FAILURE;
}
printf
(
"
Le fichier %s a été renommé en %s dans %s
\n
"
, fichierFrom, fichierTo, fichierZip);
}
else
{
/* si c'est un fichier de ce répertoire */
char
*
buf =
NULL
;
buf =
malloc
(
FILENAME_MAX*
sizeof
(
char
));
if
(
buf==
NULL
)
{
printf
(
"
Erreur d'allocation mémoire.
\n
"
);
zip_close
(
f_zip);
f_zip =
NULL
;
FREE
(
buf);
ptr =
NULL
;
return
ZIPZAP_FAILURE;
}
strcpy
(
buf,fichierTo);
strcat
(
buf,zip_get_name
(
f_zip, i, ZIP_FL_UNCHANGED)+
strlen
(
fichierFrom));
printf
(
"
%s
\n
"
,buf);
if
(
zip_rename
(
f_zip,i,buf) ==
-
1
)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
zip_close
(
f_zip);
f_zip =
NULL
;
FREE
(
buf);
ptr =
NULL
;
return
ZIPZAP_FAILURE;
}
printf
(
"
Le fichier %s a été renommé en %s dans %s
\n
"
, fichierFrom, fichierTo, fichierZip);
FREE
(
buf);
}
}
}
ptr =
NULL
;
}
else
{
/* sinon on renomme simplement le fichier trouvé par zip_name_locate à la position visu */
if
(
zip_rename
(
f_zip,visu,fichierTo) ==
-
1
)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
printf
(
"
Le fichier %s a été renommé en %s dans %s
\n
"
, fichierFrom, fichierTo, fichierZip);
}
/* lecture terminée, fermeture de l'archive */
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_SUCCESS;
}
2-D. Remplacer un fichier d'une archive zip▲
2-D-1. Algorithme▲
Ouvrir l'archive (Fonction zip_open).
Rechercher le fichier dans l'archive (Fonction zip_name_locate).
Si le fichier n'existe pas et si on a demandé de l'ajouter dans ce cas-là
ajouter le fichier (Fonction zip_add).
Sinon
le remplacer (Fonction zip_replace).
Fermer l'archive (Fonction zip_close).
2-D-2. Code source▲
/**
*
\fn
static int remplacerFichierZip(const char* fichierZip, const char* fichier, int ajout)
*
\brief
Remplace le fichier/dossier "fichier" dans l'archive zip "fichierZip".
*
*
\param
fichierZip Archive zip contenant le fichier à effacer.
*
\param
fichier Nom du fichier/dossier à remplacer.
*
\param
ajout Si le fichier n'existe pas dans l'archive, on l'ajoute ou non suivant la valeur de ajout (REPLACE_ADD ou REPLACE_NOT_ADD).
*
*
\return
ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
*/
static
int
remplacerFichierZip
(
const
char
*
fichierZip, const
char
*
fichier, int
ajout)
{
/* Source de Troumad original : http://www.developpez.net/forums/d1012322/c-cpp/c/contribuez/faq-modifier-fichier-zip/ */
/* modifié pour ajouter la gestion des erreurs et quelques fonctionnalités */
int
visu =
0
;
struct
zip *
f_zip=
NULL
;
struct
zip_source *
n_zip=
NULL
;
int
err =
0
;
f_zip=
zip_open
(
fichierZip,ZIP_CREATE,&
err);
/* s'il y a des erreurs */
if
(
err !=
ZIP_ER_OK)
{
zip_error_to_str
(
buf_erreur, sizeof
buf_erreur, err, errno);
printf
(
"
Error %d : %s
\n
"
,err, buf_erreur);
return
ZIPZAP_FAILURE;
}
/* si le fichier zip n'est pas ouvert */
if
(
f_zip==
NULL
)
{
printf
(
"
Erreur à l'ouverture du fichier %s
\n
"
, fichierZip);
return
ZIPZAP_FAILURE;
}
/* on met dans le zip_source le fichier que l'on veut remplacer */
if
((
n_zip=
zip_source_file
(
f_zip,fichier, (
off_t)0
, (
off_t)0
)) ==
NULL
)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
/* recherche de l'emplacement du fichier dans le zip */
visu=
zip_name_locate
(
f_zip,fichier,0
);
if
(
visu==-
1
)
{
printf
(
"
Le fichier %s n'existe pas dans %s
\n
"
, fichier, fichierZip);
if
(
ajout==
REPLACE_ADD)
{
/* nouveau document dans le fichier zip : le fichier n'y est pas */
/* c'est là qu'on fixe le nom qu'aura le nouveau document dans le fichier zip */
if
(
zip_add
(
f_zip,fichier,n_zip) ==
-
1
)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
zip_close
(
f_zip);
f_zip =
NULL
;
zip_source_free
(
n_zip);
n_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
printf
(
"
Le fichier %s a été ajouté dans %s
\n
"
, fichier, fichierZip);
}
else
if
(
ajout==
REPLACE_NOT_ADD)
{
printf
(
"
Le fichier %s n'a pas été ajouté ou remplacé dans %s
\n
"
, fichier, fichierZip);
}
else
{
printf
(
"
Erreur d'utilisation de la fonction %s
\n
"
, __FUNCTION__);
}
}
else
{
/* modification d'un document dans le fichier zip : le fichier est déjà dedans */
/* notre document remplace le document qui se trouve à l'emplacement visu */
if
(
zip_replace
(
f_zip,visu,n_zip) ==
-
1
)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
zip_close
(
f_zip);
f_zip =
NULL
;
zip_source_free
(
n_zip);
n_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
printf
(
"
Le fichier %s a été remplacé dans %s
\n
"
, fichier, fichierZip);
}
zip_close
(
f_zip);
f_zip =
NULL
;
zip_source_free
(
n_zip);
n_zip =
NULL
;
return
ZIPZAP_SUCCESS;
}
2-E. Extraire un fichier/dossier d'une archive zip▲
2-E-1. Algorithme▲
Ouvrir l'archive (Fonction zip_open).
Rechercher le fichier/dossier dans l'archive (Fonction zip_name_locate).
Si c'est un dossier
pour chaque élément du dossier, l'extraire (Fonction extraireFichier -> Fonctions zip_stat, zip_fopen, zip_fread, zip_fclose).
Sinon
l'extraire (Fonction extraireFichier -> Fonctions zip_stat, zip_fopen, zip_fread, zip_fclose).
Fermer l'archive (Fonction zip_close).
2-E-2. Code source▲
/**
*
\fn
static int extraireFichierZip(const char* fichierZip, const char* fichier, const char* repSortie)
*
\brief
Fonction préparant l'extraction du fichier de l'archive zip.
*
*
\param
fichierZip Archive zip contenant le fichier à extraire.
*
\param
fichier Nom du fichier/dossier à extraire.
*
\param
repSortie Le répertoire où doit être extrait le fichier de l'archive. Si repSortie vaut NULL, le répertoire est l'endroit d'où est lancée la commande.
*
\param
motdePasse Le mot de passe de l'archive protégée.
*
*
\return
ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
*/
static
int
extraireFichierZip
(
const
char
*
fichierZip, const
char
*
fichier, const
char
*
repSortie, const
char
*
motDePasse)
{
int
visu =
0
;
struct
zip *
f_zip=
NULL
;
int
err=
0
;
f_zip=
zip_open
(
fichierZip, ZIP_CHECKCONS, &
err);
/* s'il y a des erreurs */
if
(
err !=
ZIP_ER_OK)
{
zip_error_to_str
(
buf_erreur, sizeof
buf_erreur, err, errno);
printf
(
"
Error %d : %s
\n
"
,err, buf_erreur);
return
ZIPZAP_FAILURE;
}
/* si le fichier zip n'est pas ouvert */
if
(
f_zip==
NULL
)
{
printf
(
"
Erreur à l'ouverture du fichier %s
\n
"
, fichierZip);
return
ZIPZAP_FAILURE;
}
visu=
zip_name_locate
(
f_zip,fichier,0
);
if
(
visu==-
1
) /* recherche de l'emplacement du fichier dans le zip */
{
printf
(
"
Le fichier %s n'existe pas dans %s
\n
"
, fichier, fichierZip);
printf
(
"
Ajouter le caractère '/' à la fin du nom s'il s'agit d'un dossier
\n
"
);
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
/* si on demande l'extraction d'un répertoire */
/* le dernier caractère est le symbole du répertoire '/' */
if
(
fichier[strlen
(
fichier)-
1
]==
'
/
'
) /* TODO : ajouter le test pour Windows. Un simple '\' ? */
{
char
*
ptr =
NULL
;
int
i =
0
;
int
count =
zip_get_num_files
(
f_zip);
if
(
count==-
1
)
{
zip_close
(
f_zip);
f_zip =
NULL
;
printf
(
"
Erreur à l'ouverture du fichier %s
\n
"
, fichierZip);
return
ZIPZAP_FAILURE;
}
for
(
i=
0
; i<
count; i++
)
{
if
(
(
ptr=
strstr
(
zip_get_name
(
f_zip, i, ZIP_FL_UNCHANGED), fichier)) !=
NULL
)
{
/* si le fichier rencontré dans l'archive est le dossier lui-même, on ne l'extrait pas */
if
(
(
strlen
(
fichier) ==
strlen
(
ptr)) &&
(
strcmp
(
ptr,fichier)==
0
))
{
printf
(
"
Extraction des fichiers du dossier %s
\n
"
,ptr);
}
else
/* si ce sont ces fichiers, oui */
{
if
(
extraireFichier
(
i, f_zip, repSortie, motDePasse)==
ZIPZAP_FAILURE)
{
printf
(
"
Erreur à l'extraction du fichier %s
\n
"
, zip_get_name
(
f_zip, i, ZIP_FL_UNCHANGED));
zip_close
(
f_zip);
f_zip =
NULL
;
ptr =
NULL
;
return
ZIPZAP_FAILURE;
}
}
}
}
ptr =
NULL
;
}
else
{
if
(
extraireFichier
(
visu, f_zip, repSortie, motDePasse)==
ZIPZAP_FAILURE)
{
printf
(
"
Erreur à l'extraction du fichier %s
\n
"
, zip_get_name
(
f_zip, visu, ZIP_FL_UNCHANGED));
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
}
zip_close
(
f_zip);
return
ZIPZAP_SUCCESS;
}
/**
*
\fn
static int extraireFichier(int id, struct zip *f_zip, const char *repSortie)
*
\brief
Fonction ne s'occupant exclusivement que d'extraire le fichier n° "id" de l'archive "f_zip" dans "repSortie". \
Fonction appelée par extraireFichierZip et decompresserFichierZip.
*
*
\param
id Position du fichier à extraire de l'archive.
*
\param
f_zip Archive zip contenant le fichier à extraire.
*
\param
repSortie Le répertoire où doit être extrait le fichier de l'archive. Si repSortie vaut NULL, le répertoire est l'endroit d'où est lancée la commande.
*
\param
motdePasse Le mot de passe de l'archive protégée.
*
*
\return
ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
*/
static
int
extraireFichier
(
int
id, struct
zip *
f_zip, const
char
*
repSortie, const
char
*
motDePasse)
{
/* Code d'origine : */
/* http://forum.ubuntu-fr.org/viewtopic.php?pid=2596893#p2596893 Visité le 02/01/2011 */
/* http://www.siteduzero.com/forum-83-372372-p1-c-zip-et-unzip.html#r3519929 */
/* modifié pour ajouter la gestion des erreurs et quelques fonctionnalités */
struct
zip_stat file_stat;
struct
zip_file *
file_zip=
NULL
;
zip_stat_index
(
f_zip, id, 0
, &
file_stat);
/* 4. pour connaître la taille du fichier et ainsi pouvoir le lire en entier*/
if
(
zip_stat
(
f_zip, file_stat.name, 0
, &
file_stat) ==
-
1
)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
return
ZIPZAP_FAILURE;
}
printf
(
"
taille du fichier %s : %d
\n
"
, file_stat.name, (
int
)(
file_stat.size*
sizeof
(
char
)+
1
));
/* 5. on ouvre le fichier archivé */
if
(
motDePasse==
NULL
)
{
/* sans mot de passe */
file_zip=
zip_fopen
(
f_zip, file_stat.name, ZIP_FL_UNCHANGED);
}
else
{
/* avec mot de passe */
file_zip=
zip_fopen_encrypted
(
f_zip, file_stat.name, ZIP_FL_UNCHANGED, motDePasse);
}
if
(!
file_zip)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
return
ZIPZAP_FAILURE;
}
char
*
str=
NULL
;
str =
malloc
((
size_t)(
file_stat.size+
1
));
memset
(
str, 0
, (
size_t)(
file_stat.size+
1
));
if
(
str ==
NULL
)
{
printf
(
"
Erreur d'allocation mémoire
\n
"
);
return
ZIPZAP_FAILURE;
}
/* 6. on lit le fichier archivé */
if
(
zip_fread
(
file_zip, str, (
size_t)(
file_stat.size)) !=
file_stat.size)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
FREE
(
str);
zip_fclose
(
file_zip);
file_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
/* 7. on l'écrit en sortie en mode binaire */
FILE *
fOut =
NULL
;
if
(
repSortie !=
NULL
) /* si on a indiqué un répertoire de sortie */
{
char
*
repOut=
malloc
(
FILENAME_MAX *
sizeof
(
char
));
if
(
repOut ==
NULL
)
{
printf
(
"
Erreur d'allocation mémoire
\n
"
);
FREE
(
str);
zip_fclose
(
file_zip);
file_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
/* on test les '/' pour ne pas avoir affaire avec des "foo//bar/fichier" ou autres */
/* TODO : ajouter le test pour windows. Un simple '\' ? */
memset
(
repOut, 0
, FILENAME_MAX *
sizeof
(
char
));
if
(
(
repSortie[strlen
(
repSortie)-
1
]==
'
/
'
) &&
(
file_stat.name[0
]==
'
/
'
))
{
strncpy
(
repOut, repSortie, strlen
(
repSortie)-
2
);
strcat
(
repOut, file_stat.name);
}
else
if
(
(
repSortie[strlen
(
repSortie)-
1
]==
'
/
'
) ||
(
file_stat.name[0
]==
'
/
'
))
sprintf
(
repOut, "
%s%s
"
, repSortie, file_stat.name);
else
sprintf
(
repOut, "
%s/%s
"
, repSortie, file_stat.name);
/* Avant d'extraire le fichier il faut créer les répertoires nécessaires le cas échéant */
mkpath
(
repOut, 0777
);
/* si c'est autre chose qu'un dossier on l'écrit */
if
(
repOut[strlen
(
repOut)-
1
]!=
'
/
'
)
{
if
((
fOut =
fopen
(
repOut, "
wb
"
))==
NULL
)
{
printf
(
"
Erreur à la création du fichier %s
\n
"
, repOut);
FREE
(
str);
FREE
(
repOut);
zip_fclose
(
file_zip);
file_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
/* on écrit le fichier */
fwrite
(
str, sizeof
(
char
), (
size_t)file_stat.size, fOut);
fclose
(
fOut);
fOut =
NULL
;
}
zip_fclose
(
file_zip);
file_zip =
NULL
;
FREE
(
str);
FREE
(
repOut);
}
else
/* sinon on utilise le répertoire d'où est lancée la commande */
{
/* Avant d'extraire le fichier il faut créer les répertoires nécessaires le cas échéant */
mkpath
(
file_stat.name, 0777
);
/* si c'est autre chose qu'un dossier on l'écrit */
if
(
file_stat.name[strlen
(
file_stat.name)-
1
] !=
'
/
'
)
{
if
((
fOut =
fopen
(
file_stat.name, "
wb
"
))==
NULL
)
{
printf
(
"
Erreur à la création du fichier %s
\n
"
, file_stat.name);
zip_fclose
(
file_zip);
file_zip =
NULL
;
FREE
(
str);
return
ZIPZAP_FAILURE;
}
/* on écrit le fichier */
fwrite
(
str, sizeof
(
char
), (
size_t)file_stat.size, fOut);
FREE
(
str);
fclose
(
fOut);
fOut =
NULL
;
zip_fclose
(
file_zip);
file_zip =
NULL
;
}
}
FREE
(
str);
file_zip =
NULL
;
return
ZIPZAP_SUCCESS;
}
2-F. Décompresser une archive zip▲
2-F-1. Algorithme▲
Ouvrir l'archive (Fonction zip_open).
Compter le nombre d'éléments dans l'archive (Fonction zip_get_num_files).
Extraire chaque élément (Fonction extraireFichier -> Fonctions zip_stat, zip_fopen, zip_fread, zip_fclose).
Fermer l'archive (Fonction zip_close).
2-F-2. Code source▲
static
int
decompresserFichierZip
(
const
char
*
fichierZip, const
char
*
repSortie, const
char
*
motDePasse)
{
/* Code d'origine : */
/* http://www.siteduzero.com/forum-83-372372-p1-c-zip-et-unzip.html#r3519929 */
/* http://forum.ubuntu-fr.org/viewtopic.php?pid=2596893#p2596893 Visité le 02/01/2011 */
/* modifié pour ajouter la gestion des erreurs et quelques fonctionnalités */
int
err=
0
;
struct
zip *
f_zip=
NULL
;
/* 1. Ouverture de l'archive */
f_zip =
zip_open
(
fichierZip, ZIP_CHECKCONS, &
err);
/* s'il y a des erreurs */
if
(
err !=
ZIP_ER_OK)
{
zip_error_to_str
(
buf_erreur, sizeof
buf_erreur, err, errno);
printf
(
"
Error %d : %s
\n
"
,err, buf_erreur);
return
ZIPZAP_FAILURE;
}
/* si le fichier zip n'est pas ouvert */
if
(
f_zip==
NULL
)
{
printf
(
"
Erreur à l'ouverture du fichier %s
\n
"
, fichierZip);
return
ZIPZAP_FAILURE;
}
/* 2. on récupère le nombre de fichiers dans l'archive zip */
int
count =
zip_get_num_files
(
f_zip);
if
(
count==-
1
)
{
printf
(
"
Erreur à l'ouverture du fichier %s
\n
"
, fichierZip);
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
printf
(
"
Nombre de fichiers dans l'archive : %d
\n
"
, count);
int
i;
/* 3. on lit tous les fichiers */
for
(
i=
0
; i<
count; i++
)
{
/* on lance la fonction qui extraira le fichier en position "i" dans l'archive Zip */
if
(
extraireFichier
(
i, f_zip, repSortie, motDePasse)==
ZIPZAP_FAILURE)
{
printf
(
"
Erreur à l'extraction du fichier %s
\n
"
, zip_get_name
(
f_zip, i, ZIP_FL_UNCHANGED));
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_FAILURE;
}
}
/* lecture terminée, fermeture de l'archive */
zip_close
(
f_zip);
f_zip =
NULL
;
return
ZIPZAP_SUCCESS;
}
2-G. Créer une archive zip▲
2-G-1. Algorithme▲
Créer l'archive suivant le mode choisi (Fonction zip_open).
Vérifier que le fichier/dossier n'est pas déjà présent dans l'archive (Fonction verfiPresenceFichier).
Si on ajoute un dossier
on l'ajoute à l'archive (Fonction zip_add_dir),
on ajoute tous ses éléments dans l'archive (Fonction ajouteDossier ->Fonctions zip_source_file, zip_add_dir, zip_add).
Sinon
on ajoute le fichier à l'archive (Fonctions zip_source_file, zip_add).
Fermer l'archive (Fonction zip_close).
2-G-2. Code source▲
/* Ajoute les fichiers tels qu'ils sont envoyés dans la ligne de commande */
/* Pose problème avec les fichiers du style "../../fichiers" */
/**
*
\fn
static int creerFichierZip(const char* fichierZipEnSortie, int modeZip, int argc, char *arg[])
*
\brief
Créer l'archive zip "fichierZipEnSortie" suivant le mode "modeZip" avec les fichiers contenus dans *arg[].
*
*
\param
fichierZipEnSortie Le nom de l'archive zip à créer en sortie.
*
\param
modeZip Mode de création de l'archive ADD ; CREATE ou EXIST. (voir les définitions).
*
\param
argc Nombre de fichiers reçus par le programme et transmis à la fonction.
*
\param
argv Chaînes de caractères reçues par le programme et transmises à la fonction. Ces chaînes contiennent les fichiers/répertoires à ajouter.
*
*
\return
ZIPZAP_SUCCESS : Retour OK ; ZIPZAP_FAILURE : Retour d'erreur.
*/
static
int
creerFichierZip
(
const
char
*
fichierZipEnSortie, int
modeZip, int
argc, char
*
arg[])
{
struct
zip *
f_zip=
NULL
;
struct
zip_source *
doc =
NULL
;
int
err =
0
;
/* Suivant le mode choisi pour la création de l'archive on définit les flags */
if
(
modeZip==
CREATE)
{
/* on supprime l'archive pour en créer une nouvelle */
remove
(
fichierZipEnSortie);
f_zip=
zip_open
(
fichierZipEnSortie, ZIP_CREATE, &
err); /* on crée l'archive */
}
else
if
(
modeZip==
EXIST)
{
f_zip=
zip_open
(
fichierZipEnSortie, ZIP_EXCL|
ZIP_CREATE, &
err); /* on ne crée pas l'archive si elle existe, Jacques THERY2011-12-06T12:28:12.39Vous ne pensez pas que la phrase qui suit n'a pas d'utilité ?mais si elle n'existe pas on la crée */
}
else
if
(
modeZip==
ADD)
{
f_zip=
zip_open
(
fichierZipEnSortie, ZIP_CREATE, &
err); /* on crée l'archive si elle n'existe pas */
}
else
{
printf
(
"
Erreur du choix du mode
\n
"
);
usage
(
arg[0
]);
return
ZIPZAP_FAILURE;
}
/* s'il y a des erreurs */
if
(
err !=
ZIP_ER_OK)
{
zip_error_to_str
(
buf_erreur, sizeof
buf_erreur, err, errno);
printf
(
"
Error %d : %s
\n
"
,err, buf_erreur);
return
ZIPZAP_FAILURE;
}
/* si le fichier zip n'est pas ouvert */
if
(
f_zip==
NULL
)
{
printf
(
"
Erreur à l'ouverture du fichier %s
\n
"
, fichierZipEnSortie);
return
ZIPZAP_FAILURE;
}
/* on positionne i à 3 car on a dans le tableau : "0. Le nom du programme" "1. Le mode de création" "2. Le nom de l'archive" */
int
i =
3
;
for
(
; i<
argc; i++
)
{
if
(
verifPresenceFichier
(
f_zip, arg[i])==
ZIPZAP_FAILURE)
{
printf
(
"
Erreur lors de l'ajout du fichier/dossier
\"
%s
\"
à l'archive %s
\n
"
, arg[i], fichierZipEnSortie);
zip_close
(
f_zip);
f_zip =
NULL
;
zip_source_free
(
doc);
doc =
NULL
;
return
ZIPZAP_FAILURE;
}
#if defined(__POSIX_VISIBLE) || defined(_POSIX_C_SOURCE)
/* on teste si le fichier demandé est un dossier ou non */
struct
stat f_stat;
if
(
lstat
(
arg[i], &
f_stat) !=
-
1
)
{
if
(
S_ISDIR
(
f_stat.st_mode))
{
/* Si cela en est un, on l'ajoute à l'archive */
if
(
zip_add_dir
(
f_zip, arg[i]) ==
-
1
)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
zip_close
(
f_zip);
f_zip =
NULL
;
zip_source_free
(
doc);
doc =
NULL
;
return
ZIPZAP_FAILURE;
}
/* Puis on ajoute tous les fichiers du dossier et de ses sous-dossiers */
if
(
ajouteDossier
(
arg[i], f_zip)==
ZIPZAP_FAILURE)
{
printf
(
"
Erreur à l'ajout du dossier %s
\n
"
, arg[i]);
zip_close
(
f_zip);
f_zip =
NULL
;
zip_source_free
(
doc);
doc =
NULL
;
return
ZIPZAP_FAILURE;
}
}
else
/* Sinon on le traite comme un fichier normal */
{
/* que l'on récupère dans un zip_source */
if
((
doc=
zip_source_file
(
f_zip,arg[i],(
off_t)0
,(
off_t)0
))==
NULL
)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
zip_close
(
f_zip);
f_zip =
NULL
;
zip_source_free
(
doc);
doc =
NULL
;
return
ZIPZAP_FAILURE;
}
/* pour l'inclure dans l'archive */
if
(
zip_add
(
f_zip, arg[i], doc)==-
1
)
{
printf
(
"
%s
\n
"
, zip_strerror
(
f_zip));
zip_close
(
f_zip);
f_zip =
NULL
;
zip_source_free
(
doc);
doc =
NULL
;
return
ZIPZAP_FAILURE;
}
}
}
else
{
printf
(
"
Le fichier %s n'existe pas
\n
"
, arg[i]);
zip_close
(
f_zip);
f_zip =
NULL
;
zip_source_free
(
doc);
doc =
NULL
;
return
ZIPZAP_FAILURE;
}
#endif /* posix */
/* TODO : la même chose pour Windows */
}
zip_close
(
f_zip);
f_zip =
NULL
;
zip_source_free
(
doc);
doc =
NULL
;
return
ZIPZAP_SUCCESS;
}
3. Conclusion▲
Les codes sources présentés ci-dessus montrent comment il est facile avec la LibZip de réaliser les opérations classiques sur des archives. Je vous recommande l'utilisation de cette bibliothèque très puissante et très simple d'utilisation. Elle est d'ailleurs utilisée par de nombreux gros projets et ce n'est sans doute pas pour rien.
Vous pouvez télécharger le code source complet et la Makefile dans cette archive zip créée avec les exemples du code.
Télécharger ZipZap(miroir).
4. Remerciements▲
Ce document et les codes sources n'auraient pas pu exister sans la présence de codes source sur la toile. D'autres exemples d'utilisations :
- J. Leffler pour son code sur la création des dossiers avec mkdir ;
- Bernard SIAUD aka Troumad pour son exemple de modification d'un fichier zip ;
- Seldok pour l'extraction d'un fichier dans une archive zip avec libzip ;
- Claude LELOUP et jacques_jeanpour la relecture orthographique de cet article ;
et bien sûr, Dieter Baron et Thomas Klausner, auteurs de la libzip.