Eine Datenbank mit archive archivieren
Vorläufige, ungeprüfte automatische Übersetzung. Im Zweifelsfall konsultieren Sie die englische Version, die als Referenzversion gilt.
kent archive schreibt eine Datenbank in ein Austauschformat aus einer
einzigen Datei: ein Zip, das je eine NDJSON-Datei pro
Tabelle mit Daten enthält, dazu ein Manifest, das sie beschreibt, und das Quellschema.
Der Befehl ist nur lesend. kent archive öffnet die Datenbank in SQLites
Nur-Lese-Modus und schreibt nichts hinein.
Was Sie wollen: archive oder sqldump
Kent hat zwei Wege aus einer Datenbank heraus, und sie sind für verschiedene Aufgaben. Den falschen zu wählen kostet Sie später einen Umwandlungsschritt.
sqldump |
archive | |
|---|---|---|
| Erzeugt | Ein .sql-Skript | Ein Zip aus NDJSON-Dateien |
| Wofür | Die Datenbank wiederherstellen | Die Daten an ein anderes Programm übergeben |
| Gelesen von | sqlite3 oder jedem
SQLite-Werkzeug | Jeder Sprache mit einer Zip- und einer JSON-Bibliothek |
| Kann in eine Pipe gehen | Ja, wenn --out weggelassen
wird | Nein, ein Zip lässt sich nicht auf die Standardausgabe schreiben |
Wenn Sie Ihre Daten wieder in SQLite haben wollen, nehmen Sie sqldump. Wenn Sie
sie in Python lesen wollen, nehmen Sie archive.
Übersicht
kent archive --in <dbfilename> --out <archive>
Argumente
| Option | Erforderlich | Beschreibung |
|---|---|---|
--in <dbfilename> | Ja | Pfad zu einer vorhandenen
.sqlite-Datenbank, die gelesen werden soll. |
--out <archive> | Ja | Wohin das Archiv geschrieben wird. |
Beide sind erforderlich. Anders als bei sqldump gibt es
keine Standardausgabe-Variante als Rückfallebene, denn ein Zip lässt sich nicht in eine Pipe
schreiben.
$ kent archive --in mydata.sqlite
missing required flag: --out
usage: kent archive --in <dbfilename> --out <archive>
Eine Anmerkung zum Dateinamen
.kent ist die Endung dieser Archive. Sie benennt ein definiertes Format, das
Manifest, das Schema und den unten beschriebenen Aufbau je Tabelle, und nicht einen
beliebigen Ordner, dessen Inhalt Sie nach Belieben umsortieren dürfen.
Kent erzwingt sie nicht, und das ist Absicht. --out nimmt den Pfad, den Sie
angeben, es wird keine Endung geprüft oder ergänzt, und das Ergebnis ist eine gewöhnliche
Zip-Datei, die jedes Zip-Werkzeug öffnet, wie sie auch heißen mag. Eines
mydata.zip zu nennen ergibt ein vollkommen gültiges Archiv, es sagt nur nicht,
was es ist.
Was das Archiv enthält
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
...
Tabellendateien sind nummeriert und nicht nach ihrer Tabelle benannt. Ein Tabellenname
kann Zeichen enthalten, die ein Dateiname nicht zulässt, etwa Anführungszeichen, Doppelpunkt
oder Schrägstrich. Kent schreibt deshalb tables/00000001.jsonl,
tables/00000002.jsonl und so weiter, in der Reihenfolge, in der die Tabellen
geschrieben wurden. Die Nummer sagt nichts darüber aus, welche Tabelle sie enthält: Das Feld
tables[].file im Manifest stellt die Zuordnung her, und darum liest das Beispiel
unten zuerst das Manifest.
Der mimetype-Eintrag ist das, was ein .kent erkennbar macht.
Jeder andere Eintrag ist komprimiert, ohne ihn identifiziert also nichts die Datei, bis etwas
einen Teil davon entpackt. Diese 28 Bytes liegen unkomprimiert ganz vorn, wo ein Werkzeug sie
direkt aus der Datei lesen kann, derselbe Kniff, den EPUB verwendet, aus demselben Grund.
Beim eigenhändigen Lesen eines Archivs können Sie ihn ignorieren; kent restore
prüft ihn und lehnt ein Archiv ab, das ihn nicht trägt.
Eine Tabelle ohne Zeilen erzeugt keine Datei. Sie steht stattdessen mit einer Begründung im
skipped-Array des Manifests, sodass ein Programm, das das Archiv liest, eine
leere Tabelle von einer weggelassenen oder einer im Quellschema nie vorhandenen unterscheiden
kann. Ein Cordelia-Schema hat 129 Tabellen, und eine echte Datenbank befüllt rund 15 davon,
das meiste, was das Manifest beschreibt, ist also das, was nicht da ist.
Es lesen
Pythons Standardbibliothek genügt, kein Fremdpaket, und Kent oder Cordelia müssen auf dem lesenden Rechner nicht installiert sein:
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'])
Zwei Dinge an dieser Schleife sind Absicht. Sie liest eine Zeile nach der anderen, statt eine Tabelle in den Speicher zu laden, denn eine einzelne Tabelle kann zehntausende Zeilen umfassen. Und sie öffnet nur die Tabelle, die sie braucht, der Rest des Archivs wird nie entpackt, weshalb das Format ein Zip aus getrennten Dateien ist und nicht ein großes JSON-Dokument.
Zeilen sind JSON-Objekte statt Arrays, eine Spalte wird also über ihren Namen erreicht.
Das wiederholt jeden Spaltennamen in jeder Zeile, was praktisch nichts kostet: genau diese
Wiederholung entfernt die Zip-Kompression, und row['sport_id'] bekommt man weit
leichter richtig hin als row[47].
Wie Werte hinüberkommen
SQLites Speicherklassen überstehen die Reise:
| In SQLite | Im Archiv | In Python |
|---|---|---|
INTEGER | Eine JSON-Zahl | int |
REAL | Eine JSON-Zahl, immer mit Dezimalpunkt oder Exponent | float |
TEXT | Eine JSON-Zeichenkette | str |
BLOB | {"$blob": "<base64>"} |
dict |
NULL | null | None |
Ein ganzzahliger REAL behält seinen Dezimalpunkt, damit er nicht als Integer
zurückgelesen wird. Ein Blob wird in ein Objekt verpackt statt als nackte Zeichenkette
geschrieben, weil sich base64-Text nicht von gewöhnlichem Text unterscheiden lässt, der
zufällig wie base64 aussieht.
Ein Wert überlebt nicht. Not-a-number und Unendlich werden als
0.0 geschrieben, und eine eingesetzte Null ist von einer gemessenen nicht zu
unterscheiden. sqldump schreibt not-a-number
stattdessen als NULL.
Das Manifest
Eine Datei beantwortet jede strukturelle Frage zum Archiv, sodass ein Programm sie einmal liest und danach weiß, was es vor sich hat:
{
"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" } ]
}
| Feld | Was es Ihnen sagt |
|---|---|
format_version | Die Version des Archivaufbaus selbst. Ein Programm, das die Nummer nicht kennt, sollte das Archiv ablehnen, statt zu raten. |
kent, cordelia | Welche Versionen das Archiv erzeugt haben. Cordelias Angabe identifiziert das Schema. Siehe Eine Datenbank mit sqldump exportieren für den Grund. |
schema.user_version | Die Schemaversion der Quelldatenbank, lesbar, ohne irgendwelche Tabellendaten zu öffnen. |
source | Pfad, Größe und Änderungszeit der Datei, aus der es stammt. Größe und Zeit zusammen beantworten die Frage „ist das ein Archiv der Datei, die ich meine?", was ein Pfad allein nicht tut. |
counts.tables_in_schema | Gezählt in der Quelldatenbank, nicht in diesem Cordelia-Build, sodass ein Archiv einer älteren Datenbank meldet, was diese Datenbank tatsächlich hatte. |
columns | Der deklarierte SQLite-Typ jeder Spalte, in
Reihenfolge. Das ist die maßgebliche Auskunft darüber, wie ein Wert zu deuten ist, eine
JSON-1 allein sagt Ihnen nicht, ob die Spalte ein Integer oder ein
ganzzahliger Real ist. |
skipped | Tabellen ohne Datei im Archiv, und warum. Derzeit
lautet der einzige Grund empty. |
Die Bezeichnungen exported und tables_exported beschreiben den
Vorgang und nicht den Befehl, der ihn ausgeführt hat, und sie entsprechen der Zeile
-- exported: in einem kent sqldump-Kopf. Sie
sind kein Überbleibsel des früheren Befehlsnamens.
Die Referenztabellen reisen mit
Das Archiv enthält Cordelias vorbefüllte Nachschlagetabellen,
better_labels_definitions und better_labels_lookup, zusammen rund
19.700 Zeilen, statt sie als Ballast wegzulassen.
Das ist es, was das Archiv seine eigenen Fragen beantworten lässt. Eine
sport_id von 5 bedeutet für sich genommen nichts; sie zu einem
Sportnamen aufzulösen braucht diese beiden Tabellen. Ohne sie bräuchte ein Skript mit einem
Archiv in der Hand eine eigene Cordelia-Datenbank, nur um zu deuten, was es ohnehin schon
hat. Außerdem komprimieren sie ausgesprochen gut, kurzer, stark wiederholter Text kommt dem
Bestfall für ein Zip nahe.
Eine alte Datenbank wird archiviert, nicht abgelehnt
Wie sqldump und anders als
info, details
und files lehnt dieser Befehl eine Datenbank nicht ab,
deren Schemaversion von der dieses Builds abweicht. Das Manifest hält fest, welche Version es
vorgefunden hat, sodass das Archiv aussagt, was die Quelle tatsächlich war.
Ein fehlgeschlagener Lauf hinterlässt kein Archiv, auch kein unvollständiges. Ein an
--in übergebener Pfad, der nicht existiert, wird als fehlend gemeldet und
nicht angelegt:
$ kent archive --in nope.sqlite --out out.kent
kent archive: nope.sqlite does not exist
$ echo $?
1
Während des Laufs erscheint ein temporäres Verzeichnis
Tabellen werden in ein Verzeichnis geschrieben, das nach dem Archiv mit angehängtem
.staging benannt ist, neben dem Zielort des Archivs, und von dort gezippt, statt
im Speicher gehalten zu werden, eine einzelne Tabelle kann sehr groß sein. Das Verzeichnis
wird entfernt, wenn der Befehl endet, auch im Fehlerfall. Sehen Sie eines nach Kents Ende
übrig, ist das eine Meldung wert.
Es bedeutet auch, dass am Zielort gleichzeitig Platz für das Archiv und seinen Zwischenstand nötig ist.
Ein Archiv zurück in eine Datenbank lesen
kent restore baut aus einem Archiv wieder eine
.sqlite-Datei auf:
$ kent restore --in mydata.kent --out restored.sqlite
Es reproduziert die Datenbank, aus der das Archiv stammt, statt sie auf den neuesten Stand zu bringen, einschließlich ihrer Schemaversion, sodass ein Archiv einer alten Datenbank zu einer alten Datenbank zurückführt. Jeder Wert und seine Speicherklasse überstehen das, außer Keine-Zahl und Unendlich, die das Archiv von vornherein nicht tragen konnte.
Siehe auch Fehlermeldungen und Exit-Codes und Eine Datenbank mit sqldump exportieren.