Archiver une base de données avec archive

Traduction automatique provisoire, non révisée. En cas de doute, consultez la version anglaise, qui fait foi.

kent archive écrit une base de données dans une archive d'échange en un seul fichier : un zip contenant un fichier NDJSON par table contenant des données, un manifeste qui les décrit, et le schéma source.

Il est en lecture seule. kent archive ouvre la base de données dans le mode lecture seule de SQLite et n'y écrit rien.

Laquelle voulez-vous, archive ou sqldump

Kent a deux façons de sortir d'une base de données, et elles servent à des tâches différentes. Choisir la mauvaise vous coûte une étape de conversion plus tard.

sqldump archive
ProduitUn script .sqlUn zip de fichiers NDJSON
PourRecréer la base de donnéesConfier les données à un autre programme
Relu parsqlite3, ou tout outil SQLiteTout langage doté d'une bibliothèque zip et d'une bibliothèque JSON
Peut aller dans un tubeOui, quand --out est omiseNon, un zip ne peut pas être écrit sur la sortie standard

Si vous voulez récupérer vos données dans SQLite, utilisez sqldump. Si vous voulez les lire en Python, utilisez archive.

Synopsis

kent archive --in <dbfilename> --out <archive>

Arguments

OptionRequiseDescription
--in <dbfilename>OuiChemin d'une base de données .sqlite existante à lire.
--out <archive>OuiOù écrire l'archive.

Les deux sont requises. Contrairement à sqldump, il n'y a pas de forme sur sortie standard sur laquelle se rabattre, car un zip ne peut pas être écrit dans un tube.

$ kent archive --in mydata.sqlite
missing required flag: --out
usage: kent archive --in <dbfilename> --out <archive>

Une remarque sur le nom du fichier

.kent est l'extension de ces archives. Elle nomme un format défini, le manifeste, le schéma et la disposition par table décrits ci-dessous, plutôt qu'un dossier arbitraire dont le contenu serait à vous de réarranger.

Kent ne l'impose pas, et c'est délibéré. --out prend le chemin que vous lui donnez, aucun suffixe n'est vérifié ni ajouté, et le résultat est un fichier zip ordinaire que n'importe quel outil zip ouvre, quel que soit son nom. En nommer un mydata.zip vous donne une archive parfaitement valide, elle ne dit simplement pas ce qu'elle est.

Ce que contient l'archive

mydata.kent
  mimetype                 always first, uncompressed: application/vnd.venhola.kent
  manifest.json            what this archive is, and what is in it
  schema.sql               the source schema, in the same form kent sqldump --schema-only emits
  tables/00000001.jsonl    one JSON object per line, one line per row
  tables/00000002.jsonl    the manifest says which table each number holds
  ...

Les fichiers de table sont numérotés plutôt que nommés d’après leur table. Un nom de table peut contenir des caractères qu’un nom de fichier n’accepte pas, comme une apostrophe double, un deux-points ou une barre oblique ; Kent écrit donc tables/00000001.jsonl, tables/00000002.jsonl et ainsi de suite, dans l’ordre d’écriture des tables. Le numéro n’indique pas quelle table il contient : c’est le champ tables[].file du manifeste qui fait le lien, et c’est pourquoi l’exemple ci-dessous lit d’abord le manifeste.

L'entrée mimetype est ce qui rend un .kent reconnaissable. Toutes les autres entrées sont compressées : sans elle, rien n'identifie le fichier tant que quelque chose n'en a pas décompressé une partie. Ces 28 octets sont stockés sans compression tout au début, là où un outil peut les lire directement dans le fichier, la même astuce qu'EPUB, pour la même raison. Vous pouvez l'ignorer quand vous lisez une archive vous-même ; kent restore, lui, la vérifie et refuse une archive qui ne la porte pas.

Une table sans lignes ne produit pas de fichier. Elle est listée dans le tableau skipped du manifeste avec un motif, de sorte qu'un programme qui lit l'archive peut distinguer une table vide d'une table laissée de côté ou que le schéma source n'a jamais eue. Un schéma Cordelia compte 129 tables et une base réelle en peuple environ 15 : la plus grande partie de ce que décrit le manifeste est donc ce qui n'y est pas.

La lire

La bibliothèque standard de Python suffit, aucun paquet tiers, et nul besoin d'avoir Kent ou Cordelia installés sur la machine qui lit :

import zipfile, json

with zipfile.ZipFile('mydata.kent') as z:
    manifest = json.loads(z.read('manifest.json'))
    files = {t['name']: t['file'] for t in manifest['tables']}
    with z.open(files['Session']) as f:
        for line in f:
            row = json.loads(line)
            print(row['start_time'], row['sport_id'])

Deux choses dans cette boucle sont délibérées. Elle lit une ligne à la fois plutôt que de charger une table en mémoire, car une seule table peut atteindre des dizaines de milliers de lignes. Et elle n'ouvre que la table qu'elle veut, le reste de l'archive n'est jamais décompressé, ce qui est la raison pour laquelle le format est un zip de fichiers séparés plutôt qu'un seul gros document JSON.

Les lignes sont des objets JSON plutôt que des tableaux, si bien qu'on atteint une colonne par son nom. Cela répète chaque nom de colonne sur chaque ligne, ce qui ne coûte rien en pratique : la répétition est exactement ce que supprime la compression zip, et row['sport_id'] est bien plus facile à écrire correctement que row[47].

Comment les valeurs traversent

Les classes de stockage de SQLite survivent au voyage :

Dans SQLiteDans l'archiveEn Python
INTEGERUn nombre JSONint
REALUn nombre JSON, toujours avec un point décimal ou un exposantfloat
TEXTUne chaîne JSONstr
BLOB{"$blob": "<base64>"} dict
NULLnullNone

Un REAL de valeur entière garde son point décimal pour ne pas se relire comme un entier. Un blob est enveloppé dans un objet plutôt qu'écrit comme une simple chaîne, parce qu'un texte base64 est indiscernable d'un texte ordinaire qui ressemblerait à du base64.

Une valeur ne survit pas. Not-a-number et l’infini sont écrits 0.0, et un zéro substitué ne se distingue pas d’un zéro mesuré. sqldump écrit not-a-number en NULL.

Le manifeste

Un seul fichier répond à toutes les questions de structure sur l'archive : un programme le lit une fois et sait ensuite ce qu'il tient :

{
  "format_version": 1,
  "kent": "1.3.4",
  "cordelia": "1.3.3",
  "exported": "2026-08-29T14:02:11Z",
  "schema": { "user_version": 2 },
  "source": { "path": "mydata.sqlite", "size_bytes": 5492736,
              "modified": "2026-08-29T00:08:26Z" },
  "counts": { "tables_in_schema": 129, "tables_exported": 15,
              "tables_skipped": 114, "total_rows": 53673 },
  "tables": [
    { "name": "Session", "rows": 26, "file": "tables/00000001.jsonl",
      "columns": [ { "name": "sport_id", "type": "INTEGER" } ] }
  ],
  "skipped": [ { "name": "AntRx", "reason": "empty" } ]
}
ChampCe qu'il vous dit
format_versionLa version de la disposition de l'archive elle-même. Un programme qui ne reconnaît pas le numéro devrait refuser l'archive plutôt que de deviner.
kent, cordeliaQuelles versions ont produit l'archive. Celle de Cordelia est celle qui identifie le schéma. Voir Exporter une base de données avec sqldump pour la raison.
schema.user_versionLa version de schéma de la base source, lisible sans ouvrir la moindre donnée de table.
sourceLe chemin, la taille et la date de modification du fichier d'où cela provient. Taille et date ensemble répondent à « est-ce bien une archive du fichier que je crois ? », ce qu'un chemin seul ne fait pas.
counts.tables_in_schemaComptées dans la base source, pas dans cette compilation de Cordelia : une archive d'une base ancienne rapporte donc ce que cette base avait réellement.
columnsLe type SQLite déclaré de chaque colonne, dans l'ordre. C'est l'autorité sur la façon d'interpréter une valeur, un 1 JSON seul ne peut pas vous dire si la colonne est un entier ou un réel de valeur entière.
skippedLes tables sans fichier dans l'archive, et pourquoi. Aujourd'hui le seul motif est empty.

Les noms exported et tables_exported décrivent l'opération plutôt que la commande qui l'a lancée, et ils correspondent à la ligne -- exported: d'un en-tête kent sqldump. Ce ne sont pas un reliquat de l'ancien nom de la commande.

Les tables de référence voyagent avec elle

L'archive inclut les tables de référence pré-remplies de Cordelia, better_labels_definitions et better_labels_lookup, environ 19 700 lignes à elles deux, plutôt que de les laisser de côté comme du volume.

C'est ce qui permet à l'archive de répondre à ses propres questions. Un sport_id valant 5 ne signifie rien tout seul ; le résoudre en un nom de sport exige ces deux tables. Sans elles, un script détenant une archive aurait besoin d'une base Cordelia distincte rien que pour interpréter ce qu'il a déjà. Elles se compressent en outre extrêmement bien, un texte court et très répétitif est proche du meilleur cas pour un zip.

Une ancienne base est archivée, pas refusée

Comme sqldump, et contrairement à info, details et files, cette commande ne refuse pas une base dont la version de schéma diffère de celle attendue par cette compilation. Le manifeste consigne la version qu'elle a trouvée, si bien que l'archive énonce ce qu'était réellement la source.

Une exécution qui échoue ne laisse aucune archive derrière elle, ni archive partielle. Un chemin donné à --in qui n'existe pas est signalé comme manquant et n'est pas créé :

$ kent archive --in nope.sqlite --out out.kent
kent archive: nope.sqlite does not exist
$ echo $?
1

Un répertoire temporaire apparaît pendant l'exécution

Les tables sont écrites dans un répertoire nommé d'après l'archive suivi de .staging, à côté de l'endroit où l'archive va aller, et zippées depuis là plutôt que conservées en mémoire, une seule table peut être très grosse. Le répertoire est supprimé quand la commande se termine, y compris en cas d'échec. Si vous en voyez un subsister après que Kent s'est terminé, cela vaut la peine d'être signalé.

Cela veut aussi dire que la destination a besoin de place pour l'archive et son contenu préparé en même temps.

Relire une archive dans une base de données

kent restore reconstruit un fichier .sqlite à partir d'une archive :

$ kent restore --in mydata.kent --out restored.sqlite

Il reproduit la base de données dont provient l'archive plutôt que de la mettre à jour, version de schéma comprise, si bien qu'une archive d'une ancienne base restaure une ancienne base. Chaque valeur et sa classe de stockage survivent, hormis pas-un-nombre et l'infini, que l'archive ne pouvait pas transporter au départ.

Voir aussi Messages d'erreur et codes de sortie et Exporter une base de données avec sqldump.

Voir aussi