小巧。快速。可靠。
三选二。
SQLite Zipfile 模块

1. 概述

zipfile 模块提供对简单ZIP 档案的读写访问。当前实现有以下限制

将来可能会移除部分或全部这些限制。

2. 获取和编译 Zipfile

zipfile 模块的代码位于ext/misc/zipfile.c 文件中,该文件位于SQLite 主源代码树中。可以使用类似以下的命令将其编译成 SQLite 可加载扩展

gcc -g -fPIC -shared zipfile.c -o zipfile.so

或者,zipfile.c 文件可以编译到应用程序中。在这种情况下,应调用以下函数以在每个新的数据库连接中注册扩展

int sqlite3_zipfile_init(sqlite3 *db, void*, void*);

传递的第一个参数应该是要向其注册扩展的数据库句柄。第二个和第三个参数都应传递 0。

大多数命令行 shell版本都包含 Zipfile。

3. 使用 Zipfile

zipfile 模块提供了三个类似的接口来访问、更新和创建 zip 文件存档

  1. 一个表值函数,它提供对现有存档的只读访问,无论是来自文件系统还是内存。
  2. 一个虚拟表,它提供对存储在文件系统中的存档的读写访问。
  3. 一个 SQL 聚合函数,可用于在内存中创建新的存档。

zipfile 模块提供了两个类似的接口来访问 zip 存档。一个表值函数,它提供对现有存档的只读访问,以及一个虚拟表接口,它提供读写访问。

3.1. 表值函数(只读访问)

为了读取现有的 zip 存档,Zipfile 模块提供了一个表值函数,该函数接受一个参数。如果参数是文本值,则它是文件系统中要读取的 zip 存档的路径。或者,如果参数是 SQL blob,则它是 zip 存档数据本身。

例如,要检查当前目录中 zip 存档“test.zip”的内容

SELECT * FROM zipfile('test.zip');

或者,从 SQLite shell 工具(readfile() 函数读取文件系统中文件的内容并将其作为 blob 返回)

SELECT * FROM zipfile( readfile('test.zip') );

表值函数为 zip 存档中的每个记录(文件、目录或符号链接)返回一行。每一行都有以下列

列名内容
namezip 文件记录的文件名/路径。
modeUNIX 模式,由 zip 文件记录的 stat(2) 返回(整数)。这标识了记录的类型(文件、目录或符号链接),以及关联的用户/组/所有权限。
mtimeUTC 时间戳,自 UNIX 纪元以来的秒数(整数)。
sz解压缩后关联数据的字节大小(整数)。
rawdata与 zip 文件条目关联的原始(可能已压缩)数据(blob)。
data如果记录的压缩方法为 0 或 8(见下文),则为与 zip 文件条目关联的解压缩数据。或者,如果压缩方法不是 0 或 8,则此列包含 NULL 值。
method用于压缩数据的压缩方法(整数)。值 0 表示数据在 zip 存档中未经压缩存储。8 表示原始 deflate 算法。

3.2. 虚拟表接口(读写访问)

为了创建或修改现有的 zip 文件,必须在数据库模式中创建一个“zipfile”虚拟表。CREATE VIRTUAL TABLE 语句期望将 zip 文件的路径作为其唯一参数。例如,要写入当前目录中的 zip 文件“test.zip”,可以使用以下命令创建 zipfile 表

CREATE VIRTUAL TABLE temp.zip USING zipfile('test.zip');

此类虚拟表与上一节中描述的表值函数具有相同的列。可以使用 SELECT 语句以与表值函数相同的方式读取它。

使用虚拟表接口,可以通过将新行插入虚拟表来向 zip 存档添加新条目。可以通过删除行或修改行来删除条目。

3.2.1. 向 Zip 存档添加条目

可以通过插入新行来向 zip 存档添加条目。最简单的方法是仅为“name”和“data”列指定值,并让 zipfile 为其他字段填充合理的默认值。要将目录插入存档,请将“data”列设置为 NULL。例如,要将目录“dir1”和包含文本“abcdefghi”的文件“m.txt”添加到 zip 存档“test.zip”

INSERT INTO temp.zip(name, data) VALUES('dir1', NULL);           -- Add directory 
INSERT INTO temp.zip(name, data) VALUES('m.txt', 'abcdefghi');   -- Add regular file 

插入目录时,如果“name”值不以“/”字符结尾,则 zipfile 模块会在其后附加一个。这对于与处理 zip 存档的其他程序(最著名的是“info-zip”)的兼容性是必要的。

要插入符号链接,用户还必须提供“mode”值。例如,要添加从“link.txt”到“m.txt”的符号链接

INSERT INTO temp.zip(name, mode, data) VALUES('link.txt', 'lrwxrw-rw-', 'm.txt');

以下规则和注意事项适用于作为每个 INSERT 语句的一部分指定的值

说明
name必须为 name 列指定非 NULL 文本值。如果指定的名称已存在于存档中,则为错误。
mode如果将 NULL 插入 mode 列,则新存档条目的模式将自动设置为 33188(-rw-r--r--)或 16877(drwxr-xr-x),具体取决于“sz”、“data”和“rawdata”列指定的值是否指示新条目是目录。

如果指定的值是整数(或看起来像整数的文本),则按字面插入。如果该值不是有效的 UNIX 模式,则某些程序在从存档中提取文件时可能会出现意外行为。

最后,如果为该列指定的值不是整数或 NULL,则假定它是一个类似于“ls -l”命令输出的 UNIX 权限字符串(例如“-rw-r--r--”、“drwxr-xr-x”等)。在这种情况下,如果无法解析该字符串,则为错误。
mtime如果将 NULL 插入 mtime 列,则新条目的时间戳将设置为当前时间。否则,指定的值将解释为整数并按原样使用。
sz此列必须设置为 NULL。如果将非 NULL 值插入此列,或者使用 UPDATE 语句提供新的非 NULL 值,则为错误。
rawdata此列必须设置为 NULL。如果将非 NULL 值插入此列,或者使用 UPDATE 语句提供新的非 NULL 值,则为错误。
data要将目录插入存档,此字段必须设置为 NULL。在这种情况下,如果为“mode”列显式指定了值,则它必须与目录一致(即,必须为真 (mode & 0040000)=0040000)。

否则,插入此字段的值是常规文件的文本文档或符号链接的目标。
method此字段必须设置为整数 0 和 8 之一,或者设置为 NULL。

对于目录条目,将忽略插入此字段的任何值。否则,如果将其设置为 0,则文件数据或符号链接目标将按原样存储在 zip 存档中,并且压缩方法设置为 0。如果将其设置为 8,则在存储之前使用 deflate 压缩文件数据或链接目标,并将压缩方法设置为 8。最后,如果将 NULL 值写入此字段,则 zipfile 模块会自动决定是否在存储之前压缩数据。

不支持在 INSERT 语句中指定 rowid 字段的显式值。提供的任何值都会被忽略。

3.2.2. 删除 Zip 存档条目

可以通过删除相应的行来从现有 zip 存档中删除记录。例如,要使用上面创建的虚拟表从 zip 存档“test.zip”中删除文件“m.txt”

DELETE FROM temp.zip WHERE name = 'm.txt';

请注意,从 zip 存档中删除记录不会回收存档中使用的空间 - 它只是从存档的“中央目录结构”中删除一个条目,使该条目无法访问。解决此低效问题的一种方法是基于已编辑存档的内容创建新的 zip 存档。例如,在编辑通过虚拟表 temp.zzz 访问的存档后

-- Create a new, empty, archive: 
CREATE VIRTUAL TABLE temp.newzip USING zipfile('new.zip');

-- Copy the contents of the existing archive into the new archive
INSERT INTO temp.newzip(name, mode, mtime, data, method)
    SELECT name, mode, mtime, data, method FROM temp.zzz;

3.2.3. 更新现有的 Zip 存档条目

可以使用 UPDATE 语句修改现有的 zip 存档条目。

zipfile 虚拟表的最左边三列“name”、“mode”和“mtime”都可以设置为可以插入到同一列的任何值(见上文)。如果“mode”或“mtime”设置为 NULL,则最终值将根据对 NULL 值的插入进行确定 - “mtime”为当前时间,而“mode”为 33188 或 16877,具体取决于 zipfile 表的接下来的四列指定的值是否指示该条目是目录还是文件。

尝试将 sz 或 rawdata 字段设置为任何非 NULL 值都是错误的。

data 和 method 列也可以像上面为 INSERT 描述的那样设置。

3.3. zipfile() 聚合函数

可以使用 zipfile() 聚合函数完全在内存中构建新的 zip 存档。聚合函数访问的每一行都会向 zip 存档添加一个条目。返回值是一个包含整个存档图像的 blob。

zipfile() 聚合函数可以调用 2、4 或 5 个参数。如果调用 5 个参数,则添加到存档的条目等效于将相同的值插入 zipfile 虚拟表的“name”、“mode”、“mtime”、“data”和“method”列。

如果 zipfile() 调用 2 个参数,则添加到存档的条目等效于通过将相同的两个值插入 zipfile 虚拟表的“name”和“data”列添加的条目,所有其他值都设置为 NULL。如果调用 4 个参数,则等效于将 4 个值插入“name”、“mode”、“mtime”和“data”列。换句话说,以下查询对是等效的

SELECT zipfile(name, data) ...
SELECT zipfile(name, NULL, NULL, data, NULL) ...

SELECT zipfile(name, mode, mtime, data) ...
SELECT zipfile(name, mode, mtime, data, NULL) ...

例如,要创建一个包含两个文本文档“a.txt”和“b.txt”的存档,分别包含文本“abc”和“123”

WITH contents(name, data) AS (
  VALUES('a.txt', 'abc') UNION ALL
  VALUES('b.txt', '123')
)
SELECT zipfile(name, data) FROM contents;

此页面上次修改于 2023-06-07 13:17:51 UTC