Arquivar um banco de dados com archive
Tradução automática provisória, não revisada. Em caso de dúvida, consulte a versão em inglês, que é a versão de referência.
O kent archive grava um banco de dados em um arquivo de intercâmbio de um só
ficheiro: um zip contendo um arquivo NDJSON por tabela
com dados, um manifesto que os descreve e o esquema de origem.
Ele é somente leitura. O kent archive abre o banco de dados no modo somente
leitura do SQLite e não grava nada nele.
Qual você quer, archive ou sqldump
O Kent tem duas saídas de um banco de dados, e elas servem a trabalhos diferentes. Escolher a errada custa a você uma etapa de conversão depois.
sqldump |
archive | |
|---|---|---|
| Produz | Um script .sql | Um zip de arquivos NDJSON |
| Para | Recriar o banco de dados | Entregar os dados a outro programa |
| Lido de volta por | sqlite3, ou qualquer ferramenta
SQLite | Qualquer linguagem com uma biblioteca de zip e uma de JSON |
| Pode ir para um encadeamento | Sim, quando --out é
omitido | Não, um zip não pode ser gravado na saída padrão |
Se você quer seus dados de volta no SQLite, use o sqldump. Se quer lê-los em
Python, use o archive.
Sinopse
kent archive --in <dbfilename> --out <archive>
Argumentos
| Opção | Obrigatória | Descrição |
|---|---|---|
--in <dbfilename> | Sim | Caminho de um banco de
dados .sqlite existente a ler. |
--out <archive> | Sim | Onde gravar o arquivo. |
As duas são obrigatórias. Ao contrário do sqldump, não há
uma forma com saída padrão à qual recorrer, porque um zip não pode ser gravado em um
encadeamento.
$ kent archive --in mydata.sqlite
missing required flag: --out
usage: kent archive --in <dbfilename> --out <archive>
Uma observação sobre o nome do arquivo
.kent é a extensão desses arquivos. Ela nomeia um formato definido, o
manifesto, o esquema e a disposição por tabela descritos abaixo, e não uma pasta arbitrária
cujo conteúdo seja seu para rearranjar.
O Kent não a impõe, e isso é deliberado. O --out aceita o caminho que você
der, nenhum sufixo é verificado ou acrescentado, e o resultado é um arquivo zip comum que
qualquer ferramenta de zip abre, seja qual for o nome. Chamar um de mydata.zip dá
a você um arquivo perfeitamente válido, ele apenas não diz o que é.
O que o arquivo contém
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
...
Os arquivos de tabela são numerados em vez de receberem o nome da sua tabela. O nome de
uma tabela pode conter caracteres que um nome de arquivo não aceita, como aspas, dois-pontos
ou barra, então o Kent grava tables/00000001.jsonl,
tables/00000002.jsonl e assim por diante, na ordem em que as tabelas foram
gravadas. O número não diz qual tabela ele contém: o campo tables[].file do
manifesto é o que liga um ao outro, e por isso o exemplo abaixo lê o manifesto primeiro.
A entrada mimetype é o que torna um .kent reconhecível. Todas as
outras entradas são comprimidas, então sem ela nada identifica o arquivo até que algo
descomprima parte dele. Esses 28 bytes ficam armazenados sem compressão logo no início, onde
uma ferramenta pode lê-los diretamente do arquivo, o mesmo truque que o EPUB usa, pelo mesmo
motivo. Você pode ignorá-la ao ler um arquivo por conta própria; o kent restore a
verifica e recusa um arquivo que não a traga.
Uma tabela sem linhas não produz arquivo. Ela é listada no array skipped do
manifesto com um motivo, para que um programa que leia o arquivo consiga distinguir uma tabela
vazia de uma que foi deixada de fora ou que o esquema de origem nunca teve. Um esquema
Cordelia tem 129 tabelas e um banco de dados real popula cerca de 15, então a maior parte do
que o manifesto descreve é o que não está lá.
Lendo-o
A biblioteca padrão do Python basta, nenhum pacote de terceiros, e sem necessidade de ter o Kent ou o Cordelia instalados na máquina que faz a leitura:
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'])
Duas coisas nesse laço são deliberadas. Ele lê uma linha por vez em vez de carregar uma tabela na memória, porque uma única tabela pode chegar a dezenas de milhares de linhas. E abre apenas a tabela que quer, o resto do arquivo nunca é descomprimido, que é a razão de o formato ser um zip de arquivos separados em vez de um grande documento JSON.
As linhas são objetos JSON em vez de arrays, então uma coluna é alcançada pelo nome. Isso
repete cada nome de coluna em cada linha, o que na prática não custa nada: a repetição é
exatamente o que a compressão zip remove, e row['sport_id'] é bem mais fácil de
acertar do que row[47].
Como os valores atravessam
As classes de armazenamento do SQLite sobrevivem à viagem:
| No SQLite | No arquivo | Em Python |
|---|---|---|
INTEGER | Um número JSON | int |
REAL | Um número JSON, sempre com ponto decimal ou expoente | float |
TEXT | Uma string JSON | str |
BLOB | {"$blob": "<base64>"} |
dict |
NULL | null | None |
Um REAL de valor inteiro mantém seu ponto decimal para não ser relido como um
inteiro. Um blob é embrulhado em um objeto em vez de gravado como uma string solta porque
texto base64 é indistinguível de texto comum que por acaso pareça base64.
Um valor não sobrevive. Not-a-number e infinito são gravados como
0.0, e um zero substituído não se distingue de um medido.
sqldump grava not-a-number como NULL.
O manifesto
Um único arquivo responde a todas as perguntas estruturais sobre o arquivo, então um programa o lê uma vez e depois sabe o que está segurando:
{
"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" } ]
}
| Campo | O que ele diz a você |
|---|---|
format_version | A versão da própria disposição do arquivo. Um programa que não reconheça o número deve recusar o arquivo em vez de adivinhar. |
kent, cordelia | Quais versões produziram o arquivo. A do Cordelia é a que identifica o esquema. Veja Exportar um banco de dados com sqldump para o motivo. |
schema.user_version | A versão de esquema do banco de dados de origem, legível sem abrir nenhum dado de tabela. |
source | O caminho, o tamanho e a hora de modificação do arquivo de onde isso veio. Tamanho e hora juntos respondem a "este é um arquivo do ficheiro que eu penso?", o que um caminho sozinho não faz. |
counts.tables_in_schema | Contadas no banco de dados de origem, não nesta compilação do Cordelia, de modo que um arquivo de um banco mais antigo relata o que aquele banco de fato tinha. |
columns | O tipo SQLite declarado de cada coluna, em ordem.
Esta é a autoridade sobre como interpretar um valor, um 1 em JSON, sozinho,
não pode dizer se a coluna é um inteiro ou um real de valor inteiro. |
skipped | Tabelas sem arquivo no pacote, e por quê. Hoje o
único motivo é empty. |
Os nomes exported e tables_exported descrevem a operação em vez
do comando que a executou, e correspondem à linha -- exported: no cabeçalho de um
kent sqldump. Não são um resquício do nome antigo do
comando.
As tabelas de referência viajam junto
O arquivo inclui as tabelas de consulta pré-carregadas do Cordelia,
better_labels_definitions e better_labels_lookup, cerca de
19.700 linhas entre as duas, em vez de deixá-las de fora como
volume.
É isso que faz o arquivo responder às próprias perguntas. Um sport_id igual a
5 não significa nada sozinho; resolvê-lo para um nome de esporte exige essas duas
tabelas. Sem elas, um script que tivesse um arquivo precisaria de um banco de dados Cordelia
à parte só para interpretar o que já tem. Elas também comprimem extremamente bem, texto curto
e muito repetitivo está perto do melhor caso para um zip.
Um banco de dados antigo é arquivado, não recusado
Como o sqldump, e ao contrário de
info, details e
files, este comando não recusa um banco de dados cuja
versão de esquema difere da que esta compilação espera. O manifesto registra a versão que
encontrou, então o arquivo declara o que a origem realmente era.
Uma execução que falha não deixa arquivo algum para trás, nem um parcial. Um caminho dado a
--in que não existe é relatado como ausente e não é criado:
$ kent archive --in nope.sqlite --out out.kent
kent archive: nope.sqlite does not exist
$ echo $?
1
Um diretório temporário aparece enquanto ele roda
As tabelas são gravadas em um diretório com o nome do arquivo acrescido de
.staging, ao lado de onde o arquivo vai ficar, e zipadas de lá em vez de mantidas
em memória, uma única tabela pode ser muito grande. O diretório é removido quando o comando
termina, inclusive quando falha. Se você vir um sobrando depois que o Kent saiu, vale a pena
relatar.
Isso também significa que o destino precisa de espaço para o arquivo e para seu conteúdo em preparação ao mesmo tempo.
Ler um arquivo de volta para um banco de dados
O kent restore reconstrói um ficheiro
.sqlite a partir de um arquivo:
$ kent restore --in mydata.kent --out restored.sqlite
Ele reproduz o banco de dados de que o arquivo veio em vez de atualizá-lo, inclusive sua versão de esquema, então um arquivo de um banco antigo restaura para um banco antigo. Todo valor e sua classe de armazenamento sobrevivem, exceto não-um-número e infinito, que o arquivo não podia carregar desde o início.
Veja também Mensagens de erro e códigos de saída e Exportar um banco de dados com sqldump.