有时候只想读一个 SQLite 数据库,不希望程序有任何机会改到它。Python 自带的 sqlite3 支持用 URI 的方式打开数据库,在后面加上 ?mode=ro 就是只读。
出问题的写法
我一开始是这样拼链接的:
import sqlite3
import urllib.parse
from pathlib import Path
path = Path("data/shop.db").resolve()
uri = "file:" + urllib.parse.quote(str(path), safe="/") + "?mode=ro"
conn = sqlite3.connect(uri, uri=True)
在 Linux 上路径是 /home/me/data/shop.db,拼出来没问题。到了 Windows,str(path) 变成 D:\data\shop.db:冒号和反斜杠都不在 safe 里,被转成了 D%3A%5Cdata%5Cshop.db,SQLite 认不出这是一个文件,于是报 unable to open database file。
改成用 Path.as_uri()
path = Path("data/shop.db").resolve()
uri = path.as_uri() + "?mode=ro" # Windows: file:///D:/data/shop.db?mode=ro
conn = sqlite3.connect(uri, uri=True)
conn.execute("PRAGMA query_only = ON")
as_uri() 会按各个系统的规矩生成标准的 file: 链接:Windows 上盘符前面是三个斜杠,反斜杠换成正斜杠,中文目录名也会正确转义。它只接受绝对路径,所以前面要先 resolve()。
两道保险
mode=ro:以只读方式打开文件,任何写操作都会报错。PRAGMA query_only = ON:让这个连接拒绝一切修改语句,多一层保险。
凡是要在 Windows 和 Linux 上都跑的代码,路径别自己拼字符串,交给 pathlib 去处理。