zip v0.3.0
Zip archive module for YScript
yes.exe ypack install zip@0.3.0
| Auteur | Yan Grenier |
| Publié le | 2026-08-10T14:00:12+00:00 |
| Checksum | sha256:c4ca8fd4fb9a87239029bf9ebd05ac6b91052517de4f9b834fca546e62285f78 |
| Moteur requis |
yscript >=0.3.0 |
| Fournit | module |
Dépendances
Aucune dépendance.
Téléchargement
Archive .zip de la version 0.3.0
Historique des versions
| Version | Date |
|---|---|
| 0.3.0 (dernière) | 2026-08-10T14:00:12+00:00 |
Documentation
Module zip
Le module zip permet de manipuler des archives Zip depuis un script YScript : ouvrir une archive existante ou en créer une nouvelle, lister son contenu, ajouter/remplacer/supprimer des entrées, et compresser/décompresser un dossier entier.
require("io")
local zip = require("zip")
local ar = zip.open("package.zip", "a")
for _, e in ipairs(ar:entries()) do
print(e.name, e.size, e.isdirectory)
end
ar:add("readme.txt", "hello")
ar:close()
Prérequis : la bibliothèque io
zip n'a aucune fonctionnalité qui ne touche pas au système de fichiers : une archive est un fichier, ajouter une entrée depuis un dossier lit des fichiers, compresser un dossier les parcourt. La bibliothèque io est donc une dépendance obligatoire de tout le module (contrairement à des modules comme http, où io n'est nécessaire qu'à certaines fonctions).
io doit être chargée avant zip :
require("io") -- ou l'hôte a déjà appelé OpenIOLib()
local zip = require("zip")
Si io n'est pas chargée, require("zip") échoue (l'erreur remonte comme n'importe quel loader qui échoue — utilisez pcall(require, "zip") si vous voulez récupérer nil, message plutôt que de laisser l'erreur se propager) :
local ok, err = pcall(require, "zip")
if not ok then
print("zip indisponible : " .. tostring(err))
end
Vue d'ensemble
| Fonction / méthode | Description |
|---|---|
zip.open(path [, mode]) | Ouvre ou crée une archive, retourne l'objet archive |
zip.type(obj) | "archive" / "closed archive" / nil |
zip.extractall(zippath, destdir [, overwrite]) | Décompresse une archive entière vers un dossier |
zip.compressdir(srcdir, destzippath [, options]) | Compresse un dossier entier vers une nouvelle archive |
archive:entries() | Liste le contenu de l'archive |
archive:exists(name) | Teste la présence d'une entrée |
archive:read(name) | Lit le contenu d'une entrée en mémoire |
archive:add(name, content) | Ajoute une nouvelle entrée depuis une chaîne |
archive:addfile(name, filepath) | Ajoute une nouvelle entrée depuis un fichier du disque |
archive:replace(name, content) | Remplace le contenu d'une entrée existante |
archive:remove(name) | Supprime une entrée |
archive:extract(name, destpath [, overwrite]) | Extrait une entrée vers un fichier du disque |
archive:extractall(destdir [, overwrite]) | Extrait toutes les entrées vers un dossier |
archive:close() | Referme l'archive |
L'objet archive
zip.open retourne un objet archive (un userdata avec ses propres méthodes, dans le même esprit qu'un FILE* retourné par io.open). Il doit être refermé explicitement par archive:close(), implicitement via l'attribut <close>, ou en dernier recours par le ramasse-miettes :
local ar <close> = zip.open("package.zip", "r")
-- ar:close() est appelé automatiquement en sortie de bloc
Utiliser une méthode sur une archive déjà fermée lève une erreur.
zip.open(path [, mode])
Ouvre une archive existante ou en crée une nouvelle. mode (chaîne, défaut "r") :
| Mode | Comportement |
|---|---|
"r" | Lecture seule. Erreur (nil, message) si le fichier n'existe pas ou n'est pas un zip valide. |
"w" | Nouvelle archive vide. Écrase silencieusement un fichier existant au même chemin. |
"a" | Ouvre l'archive existante en modification, ou en crée une vide si elle n'existe pas encore. Permet ajout/remplacement/suppression. |
En cas d'échec (fichier absent en "r", contenu invalide, erreur disque...), zip.open retourne nil suivi d'un message d'erreur — comme io.open — plutôt que de lever une erreur script :
local ar, err = zip.open("introuvable.zip", "r")
if not ar then
print("échec : " .. err)
return
end
Un mode autre que "r"/"w"/"a" est en revanche une erreur de programmation et lève une erreur script immédiate (mauvais argument), pas un nil, message.
zip.type(obj)
Miroir de io.type : retourne "archive" si obj est une archive ouverte, "closed archive" si elle est fermée, ou nil si obj n'est pas une archive de ce module.
local ar = zip.open("a.zip", "w")
print(zip.type(ar)) --> archive
ar:close()
print(zip.type(ar)) --> closed archive
print(zip.type("x")) --> nil
archive:entries()
Retourne un tableau (indices 1..n) décrivant chaque entrée de l'archive :
| Champ | Type | Description |
|---|---|---|
name | string | Chemin de l'entrée dans l'archive, séparateur / |
size | integer | Taille décompressée en octets |
compressedsize | integer | Taille compressée en octets |
lastmodified | integer | Horodatage (epoch, secondes) — même unité que os.time() |
isdirectory | boolean | true si l'entrée représente un dossier (nom finissant par /) |
local ar = zip.open("package.zip", "r")
for _, e in ipairs(ar:entries()) do
print(string.format("%-30s %8d -> %8d octets", e.name, e.size, e.compressedsize))
end
ar:close()
archive:exists(name)
Retourne true/false selon la présence d'une entrée name (fichier ou dossier) dans l'archive. Utile avant :add/:replace/:remove, qui sont volontairement stricts (voir plus bas) :
if ar:exists("config.json") then
ar:replace("config.json", newContent)
else
ar:add("config.json", newContent)
end
archive:read(name)
Retourne le contenu entier de l'entrée name sous forme de chaîne binaire (un caractère = un octet, même convention que le mode binaire de io) — pratique pour les petits fichiers texte/JSON, mais charge tout le contenu en mémoire de script. Pour un gros fichier, préférez :extract qui passe par un flux sans tout charger.
Erreurs : entrée absente, ou entrée désignant un dossier.
local ar = zip.open("package.zip", "r")
local manifest = ar:read("package.json")
ar:close()
archive:add(name, content) / archive:addfile(name, filepath)
Créent une nouvelle entrée name. Une entrée déjà présente sous ce nom est une erreur (pas d'écrasement implicite — utilisez :replace, ou testez :exists au préalable si vous voulez un comportement « upsert »).
:add(name, content)— le contenu vient d'une chaîne de script (binaire, comme:read).:addfile(name, filepath)— le contenu vient d'un fichier du disque, copié en flux vers l'entrée
sans être chargé intégralement en mémoire de script. Préférable pour les gros fichiers. Erreur si filepath n'existe pas sur le disque.
local ar = zip.open("package.zip", "a")
ar:add("VERSION", "1.0.0\n")
ar:addfile("dist/app.dll", "bin/Release/app.dll")
ar:close()
archive:replace(name, content)
Remplace le contenu d'une entrée déjà présente. Le format Zip ne permettant pas de modifier une entrée en place, ceci équivaut en interne à une suppression suivie d'un ajout — transparent pour le script, mais à garder en tête si vous inspectez le flux de l'archive par un autre moyen pendant l'opération. Erreur si name est absente (symétrique de :add).
ar:replace("VERSION", "1.0.1\n")
archive:remove(name)
Supprime l'entrée name. Erreur si elle est absente.
ar:remove("old-file.txt")
archive:extract(name, destpath [, overwrite])
Extrait l'entrée name directement vers le fichier destpath du disque, en flux (sans charger le contenu en mémoire de script — pendant symétrique de :addfile).
overwrite (booléen, défaut false) : si destpath existe déjà et overwrite n'est pas true, c'est une erreur — pas d'écrasement silencieux d'un fichier existant.
Erreur si l'entrée est absente, ou si elle désigne un dossier (utilisez :extractall ou io.mkdir pour un dossier).
local ar = zip.open("package.zip", "r")
ar:extract("bin/app.dll", "install/app.dll", true) -- true = écrase si déjà présent
ar:close()
archive:extractall(destdir [, overwrite])
Extrait toutes les entrées vers destdir, en recréant la structure de dossiers automatiquement (sous-dossiers créés au besoin). overwrite a la même sémantique que pour :extract, appliquée à chaque fichier extrait.
local ar = zip.open("package.zip", "r")
ar:extractall("installed/mypackage", true)
ar:close()
archive:close()
Referme l'archive : persiste les modifications en attente (pour une archive ouverte en "w"/"a") et referme le fichier sous-jacent. Idempotent — un second :close() ne fait rien.
zip.extractall(zippath, destdir [, overwrite])
Raccourci équivalent à zip.open(zippath, "r"):extractall(destdir, overwrite) suivi d'un :close() automatique. Pratique pour un cas d'usage en un seul appel, par exemple installer un paquet téléchargé :
zip.extractall("mypackage-1.0.0.zip", "installed/mypackage", true)
zip.compressdir(srcdir, destzippath [, options])
Crée une nouvelle archive à destzippath et y ajoute récursivement tout le contenu de srcdir, avec des chemins d'entrée relatifs à srcdir (séparateur /, y compris depuis un hôte Windows). Une erreur est levée si srcdir n'existe pas.
options (table optionnelle) :
| Option | Défaut | Description |
|---|---|---|
overwrite | false | Si destzippath existe déjà et overwrite n'est pas true, c'est une erreur (contrairement à zip.open(path, "w"), qui écrase toujours — ici l'écrasement en masse doit être explicite). |
includebase | false | Si true, les entrées sont préfixées par le nom du dossier srcdir lui-même (srcdir/fichier.txt) plutôt que par son seul contenu (fichier.txt). |
-- Sans includebase : les entrées sont "fichier.txt", "sub/nested.txt", ...
zip.compressdir("dist/mypackage", "mypackage-1.0.0.zip", { overwrite = true })
-- Avec includebase : les entrées sont "mypackage/fichier.txt", "mypackage/sub/nested.txt", ...
zip.compressdir("dist/mypackage", "mypackage-1.0.0.zip", { includebase = true })
Erreurs
Les erreurs de programmation (mauvais type/valeur d'argument, mode invalide, méthode appelée sur une archive fermée, opération incohérente comme ajouter une entrée déjà présente) sont levées comme des erreurs script classiques — à capturer avec pcall si nécessaire. Seul zip.open fait exception pour les échecs liés au système de fichiers (archive absente en lecture, contenu invalide, erreur disque) : il retourne nil, message, comme io.open.
| Situation | Comportement |
|---|---|
require("zip") sans io chargée | require échoue (erreur du loader) |
zip.open(path, "r") sur un fichier absent | nil, message |
zip.open(path, "r") sur un fichier qui n'est pas un zip valide | nil, message |
zip.open(path, mode) avec un mode autre que "r"/"w"/"a" | erreur script (mauvais argument) |
| Méthode appelée sur une archive déjà fermée | erreur script |
:add/:addfile sur un nom déjà présent | erreur script |
:read/:replace/:remove/:extract sur un nom absent | erreur script |
:read/:extract visant une entrée qui est un dossier | erreur script |
:addfile avec un fichier disque absent | erreur script |
:extract/:extractall vers un chemin existant sans overwrite | erreur script |
zip.compressdir avec un srcdir absent | erreur script |
zip.compressdir sans overwrite sur une destination déjà existante | erreur script |
Exemple complet
require("io")
local zip = require("zip")
-- Empaqueter un dossier de sources en une archive
zip.compressdir("dist/mypackage", "mypackage-1.0.0.zip", { overwrite = true })
-- Inspecter le contenu d'une archive
local ar = zip.open("mypackage-1.0.0.zip", "r")
for _, e in ipairs(ar:entries()) do
print(e.name, e.size, e.isdirectory)
end
local manifest = ar:read("package.json")
ar:close()
-- Construire/mettre à jour une archive entrée par entrée
local pkg = zip.open("mypackage-1.0.0.zip", "a")
pkg:replace("package.json", manifest .. "\n-- updated")
pkg:addfile("CHANGELOG.md", "CHANGELOG.md")
pkg:remove("old-file.txt")
pkg:close()
-- "Installer" un paquet : tout extraire dans un dossier
zip.extractall("mypackage-1.0.0.zip", "installed/mypackage", true)
Limites connues (v1)
- Pas de support des mots de passe / chiffrement d'archive.
:replacen'est pas une opération atomique au niveau du fichier zip (suppression + ajout en
interne).
- Pas de contrôle fin du niveau de compression par entrée.
- Pas de préservation de métadonnées spécifiques à une plateforme (permissions Unix, attributs
Windows, liens symboliques).