zipfile 模块提供对简单ZIP 档案的读写访问。当前实现有以下限制
将来可能会移除部分或全部这些限制。
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。
zipfile 模块提供了三个类似的接口来访问、更新和创建 zip 文件存档
zipfile 模块提供了两个类似的接口来访问 zip 存档。一个表值函数,它提供对现有存档的只读访问,以及一个虚拟表接口,它提供读写访问。
为了读取现有的 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 存档中的每个记录(文件、目录或符号链接)返回一行。每一行都有以下列
列名 | 内容 |
---|---|
name | zip 文件记录的文件名/路径。 |
mode | UNIX 模式,由 zip 文件记录的 stat(2) 返回(整数)。这标识了记录的类型(文件、目录或符号链接),以及关联的用户/组/所有权限。 |
mtime | UTC 时间戳,自 UNIX 纪元以来的秒数(整数)。 |
sz | 解压缩后关联数据的字节大小(整数)。 |
rawdata | 与 zip 文件条目关联的原始(可能已压缩)数据(blob)。 |
data | 如果记录的压缩方法为 0 或 8(见下文),则为与 zip 文件条目关联的解压缩数据。或者,如果压缩方法不是 0 或 8,则此列包含 NULL 值。 |
method | 用于压缩数据的压缩方法(整数)。值 0 表示数据在 zip 存档中未经压缩存储。8 表示原始 deflate 算法。 |
为了创建或修改现有的 zip 文件,必须在数据库模式中创建一个“zipfile”虚拟表。CREATE VIRTUAL TABLE 语句期望将 zip 文件的路径作为其唯一参数。例如,要写入当前目录中的 zip 文件“test.zip”,可以使用以下命令创建 zipfile 表
CREATE VIRTUAL TABLE temp.zip USING zipfile('test.zip');
此类虚拟表与上一节中描述的表值函数具有相同的列。可以使用 SELECT 语句以与表值函数相同的方式读取它。
使用虚拟表接口,可以通过将新行插入虚拟表来向 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 字段的显式值。提供的任何值都会被忽略。
可以通过删除相应的行来从现有 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;
可以使用 UPDATE 语句修改现有的 zip 存档条目。
zipfile 虚拟表的最左边三列“name”、“mode”和“mtime”都可以设置为可以插入到同一列的任何值(见上文)。如果“mode”或“mtime”设置为 NULL,则最终值将根据对 NULL 值的插入进行确定 - “mtime”为当前时间,而“mode”为 33188 或 16877,具体取决于 zipfile 表的接下来的四列指定的值是否指示该条目是目录还是文件。
尝试将 sz 或 rawdata 字段设置为任何非 NULL 值都是错误的。
data 和 method 列也可以像上面为 INSERT 描述的那样设置。
可以使用 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