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
ErzeugtEin .sql-SkriptEin Zip aus NDJSON-Dateien
WofürDie Datenbank wiederherstellenDie Daten an ein anderes Programm übergeben
Gelesen vonsqlite3 oder jedem SQLite-WerkzeugJeder Sprache mit einer Zip- und einer JSON-Bibliothek
Kann in eine Pipe gehenJa, wenn --out weggelassen wirdNein, 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

OptionErforderlichBeschreibung
--in <dbfilename>JaPfad zu einer vorhandenen .sqlite-Datenbank, die gelesen werden soll.
--out <archive>JaWohin 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 SQLiteIm ArchivIn Python
INTEGEREine JSON-Zahlint
REALEine JSON-Zahl, immer mit Dezimalpunkt oder Exponentfloat
TEXTEine JSON-Zeichenkettestr
BLOB{"$blob": "<base64>"} dict
NULLnullNone

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" } ]
}
FeldWas es Ihnen sagt
format_versionDie Version des Archivaufbaus selbst. Ein Programm, das die Nummer nicht kennt, sollte das Archiv ablehnen, statt zu raten.
kent, cordeliaWelche Versionen das Archiv erzeugt haben. Cordelias Angabe identifiziert das Schema. Siehe Eine Datenbank mit sqldump exportieren für den Grund.
schema.user_versionDie Schemaversion der Quelldatenbank, lesbar, ohne irgendwelche Tabellendaten zu öffnen.
sourcePfad, 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_schemaGezählt in der Quelldatenbank, nicht in diesem Cordelia-Build, sodass ein Archiv einer älteren Datenbank meldet, was diese Datenbank tatsächlich hatte.
columnsDer 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.
skippedTabellen 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.

Siehe auch