小巧、快速、可靠。
任選三項。
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。

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 檔案中的每個記錄(檔案、目錄或符號連結)返回一行。每一行都有以下欄位

欄位名稱內容
name zip 檔案記錄的檔案名稱/路徑。
mode UNIX 模式,由 stat(2) 為 zip 檔案記錄返回(一個整數)。這會識別記錄的類型(檔案、目錄或符號連結),以及相關的使用者/群組/所有權限。
mtime UTC 時間戳記,以自 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 文字值。如果指定的 name 已存在於檔案庫中,則會產生錯誤。
mode 如果將 NULL 插入 mode 欄位,則新檔案庫條目的模式會自動設定為 33188 (-rw-r--r--) 或 16877 (drwxr-xr-x),視欄位「sz」、「data」和「rawdata」指定的值是否指出新條目為目錄而定。

如果指定的值為整數(或看起來像整數的文字),則會逐字插入。如果該值不是有效的 UNIX 模式,則某些程式在從檔案庫中擷取檔案時可能會產生異常行為。

最後,如果為此欄位指定的不是整數或 NULL,則會假設它為 UNIX 權限字串,類似於「ls -l」指令所輸出的字串(例如「-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 虛擬表格的左邊三欄「名稱」、「模式」和「修改時間」,每個都可以設定為可以插入到相同欄位中的任何值 (請見上文)。如果「模式」或「修改時間」設定為 NULL,最終值會根據 NULL 值的 INSERT 方式決定 - 「修改時間」為目前時間,「模式」為 33188 或 16877,視 zipfile 表格的後四個欄位所指定的值是否指出項目是目錄或檔案而定。

嘗試將 sz 或 rawdata 欄位設定為 NULL 以外的任何值都是錯誤的。

資料和方法欄位也可以如上文 INSERT 所述進行設定。

3.3. zipfile() 聚合函數

新的 zip 檔案可以使用 zipfile() 聚合函數完全在記憶體中建構。聚合函數拜訪的每列都會新增一個項目到 zip 檔案中。回傳的值是一個 blob,包含整個檔案映像。

zipfile() 聚合函數可以呼叫 2、4 或 5 個參數。如果呼叫 5 個參數,則新增到檔案中的項目等同於將相同的值插入到 zipfile 虛擬表格的「名稱」、「模式」、「修改時間」、「資料」和「方法」欄位中。

如果 zipfile() 呼叫 2 個參數,則新增到檔案中的項目等同於將相同的兩個值插入到 zipfile 虛擬表格的「名稱」和「資料」欄位中,所有其他值都設定為 NULL。如果呼叫 4 個參數,則等同於將 4 個值插入到「名稱」、「模式」、「修改時間」和「資料」欄位中。換句話說,以下查詢對等同

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