新闻详情

新闻详情

首页 / 资讯中心 / 详情

SQLite加密插件QtCipher:从编译到实战的完整指南

发布时间:2026/9/26 21:24:56来源:尧图网络
SQLite加密插件QtCipher:从编译到实战的完整指南
简介Sqlite加密插件QtCipher是一套基于Qt和sqlitecipher库的SQLite数据库加密工程面向需要轻量级本地存储安全能力的Qt开发者。该工程通过插件方式对数据库文件进行加解密处理适用于桌面应用、移动端及嵌入式系统中的敏感数据保护可有效降低数据泄露风险。压缩包共23个文件、约2.43MB包含5个cpp源文件、4个h头文件、4个pro工程文件以及README、CHANGELOG、许可证等配套文档目录结构清晰可直接通过QtCreator加载编译将生成的插件安装至对应Qt版本的QtCreator插件目录。已有140人学习浏览说明该方案在中小型项目中具备一定参考价值。通过这份工程开发者可以快速掌握SQLite加密插件的集成方式复用插件框架与加密调用逻辑结合demo示例理解加密数据库的创建、打开及常规操作流程从而不必从零编写底层加密算法即可为应用增添可靠的数据库安全层。1. SQLite 加密插件 QtCipher轻量数据库也该有一层密文保护接手一个桌面客户端时我发现客户把整个数据目录直接拷走里面的 SQLite 库文件用 DB Browser 一开客户信息、订单记录全像没穿衣服一样摊在桌面上。那是我第一次意识到轻量不等于安全Sqlite 数据库本身不提供加密谁拿到文件谁就拿到了全部数据。后来换用 QtCipherSqlitePlugin把 sqlitecipher 的加密能力封装成 Qt 的 QSQLCIPHER 驱动应用层代码几乎不用动库文件就变成了一堆无法识别的密文。这篇笔记适合手里已有 Qt 项目、想把 SQLite 从“裸存”升级为“加密存储”的开发者也适合第一次听说 SQLite 加密插件、想知道它到底怎么装的入门者。2. 编译与安装从解压到 QtCreator 插件目录的完整路线很多人拿到压缩包后先找现成的 dll结果发现里面根本没有二进制产物。这是因为压缩包是以 Qt 工程形式提供的需要你本机先装好 Qt 环境再自己编译。这恰恰是它的优势插件和你的 Qt 版本、编译器绑定而不是给你一个固定环境下才能跑的二进制省去了一堆兼容性麻烦。下面按步骤走一遍。2.1 先看懂压缩包里四个角色插件工程、demo、测试工程、文档解压QtCipherSqlitePlugin-wang.zip之后根目录下能看到QtCipherSqlitePlugin.pro、sqlitecipher、demo、test_plugin几个核心部分以及README.md、CHANGELOG.md、License、.qmake.conf等伴随文件。第一次接触的人容易被目录数量吓到其实只要分清职责就不会乱。QtCipherSqlitePlugin.pro插件主工程构建目标是一个 Qt 插件 dll也就是后面要装进 QtCreator 的那个文件。sqlitecipher核心源码目录基于 sqlite3 体系把 SQLCipher 的加密实现集成进 Qt 的 SQL 驱动框架。插件里的加密逻辑都在这里编译时会一起构建。demo演示工程展示加密库的打开、建表、插入、查询完整流程普通使用者可以直接拿它当模板。test_plugin回归测试工程主要是作者用来验证插件能否正常加载和跑通基本功能普通使用不用管它。README.md和CHANGELOG.md前者是用法说明后者是各版本变更记录。升级前先翻一遍 CHANGELOG能避开不少已知问题。这套插件的工作原理说白了就一句话它实现了一个 Qt 的数据库驱动插件向 Qt 注册名为QSQLCIPHER的驱动。当你的代码调用QSqlDatabase::addDatabase(QSQLCIPHER)时Qt 通过插件机制加载它之后所有QSqlQuery操作都走这个驱动而驱动底层调用 SQLCipher 的加密 API 完成数据页的加解密。对上层业务代码来说感知不到加密过程。2.2 命令行编译qmake、nmake / mingw32-make 三步走编译前先确认前置条件本机装了 Qt 5.15 或 Qt 6 的对应开发套件以及配套编译器。所谓“配套”指的是位数和编译器类型要一致比如 Qt 是 msvc2019_64 就配 MSVC 2019是 mingw81_64 就配 MinGW。混用是编译期或运行期翻车的第一大来源。命令行编译的方式最直观也最容易复现cd QtCipherSqlitePlugin-wang mkdir -p build cd build C:/Qt/Qt5.15.2/5.15.2/msvc2019_64/bin/qmake.exe ../QtCipherSqlitePlugin.pro -spec win32-msvc nmake如果你用的是 MinGW 套件qmake 之后不要用 nmake换成 mingw32-makeC:/Qt/Qt5.15.2/5.15.2/mingw81_64/bin/qmake.exe ../QtCipherSqlitePlugin.pro C:/Qt/Qt5.15.2/Tools/mingw810_64/bin/mingw32-make.exe这里的 qmake 路径要替换成你自己机器上的实际安装位置。该工程引用的示例路径是C:\Qt\QtX.XX.XX\Tools\QtCreator\lib\qtcreator\plugins其中QtX.XX.XX是具体版本号比如Qt5.15.2。-spec win32-msvc是告诉 qmake 用 MSVC 的平台规范MinGW 套件下不用传qmake 会自动从工具链推断。构建成功后会生成release/sqlitecipher.dllrelease 模式或debug/sqlitecipherd.dlldebug 模式。注意不要在源码目录里直接跑 qmake一定要先建一个外部 build 目录否则生成的中间文件会把源码目录搞乱后面想升级插件时还要先清理。如果不想敲命令行直接用 QtCreator 打开QtCipherSqlitePlugin.pro选择对应构建套件后点“构建”按钮效果完全一样。我一般建议新手走 QtCreator 这条路少记一堆路径。构建过程中如果报错提示找不到 OpenSSL 头文件或 lib 文件说明本机缺 SQLCipher 依赖的 OpenSSL常见做法是下载对应 win64 版本的预编译 OpenSSL然后在 pro 文件里把INCLUDEPATH和LIBS指向它重新 qmake 后再构建。2.3 安装到 QtCreator插件 dll 放哪、怎么确认加载成功了编译产物拿到手后下一步是把它复制到 QtCreator 的插件目录。注意这个路径是 QtCreator 自己的插件目录不是 Qt 库的 plugins 目录很多人就是在这里放错位置导致插件加载失败。cp release/sqlitecipher.dll C:/Qt/Qt5.15.2/Tools/QtCreator/lib/qtcreator/plugins/在纯 Windows 环境没有 cp 命令的话用资源管理器直接复制粘贴或者用 PowerShell 的Copy-Item都行。路径里的Qt5.15.2换成你自己的 Qt 版本号如果 QtCreator 是独立安装的就换成它的实际安装目录。复制完成后重启 QtCreator打开菜单Help - About Plugins搜索sqlcipher或QtCipher如果列表里能看到对应插件说明安装成功。此时再去编译运行 demo 工程应该能正常创建加密库并对数据做增删改查。如果 About Plugins 里找不到先别急着怀疑插件坏了。QtCreator 的插件加载日志通常在%APPDATA%\QtProject\qtcreator\QtCreator.logWindows或~/.config/QtProject/qtcreator/下打开日志看有没有加载失败的记录大部分问题在日志里都有明确原因。3. 核心 API 与加密原理SQLCipher 的四组参数与 Qt 连接写法插件装好只是开始真正要理解的是它背后的加密参数。这些参数决定了这个库以后还能不能打开、换台电脑能不能迁移也是实际项目里排查问题的关键所在。这一章把原理和代码放在一起讲。3.1 SQLCipher 加密体系一句话讲清SQLCipher 不是对整个文件做一次性加密而是按页加密。默认每页 4096 字节文件头保存随机 salt每个数据页除了密文还有 HMAC 校验值。打开数据库时你用代码提供的密码加上文件头的 salt经过 PBKDF2 密钥派生函数算出真正的 256 位 AES 密钥再用这个密钥逐页解密。正因为 salt 每次随机同一个密码创建的库文件每次都不一样但只要密码和相关参数正确都能正常打开。参数不匹配是“文件打不开”现象里最大的来源。以下是几组关键参数参数SQLCipher 3.x 默认SQLCipher 4.x 默认说明cipheraes-256-cbcaes-256-cbc数据页加密算法kdf_iter64000256000PBKDF2 迭代次数越大越难暴力破解cipher_page_size40964096SQLite 页大小建库后不可改hmac_algorithmHMAC_SHA1HMAC_SHA512数据页完整性校验算法这套参数在 QtCipher 的驱动里都有默认值一般情况不用手写。但一旦库是别的环境建的参数不一样你这边就会打开失败。记住这张表第 5 章排错时要反复用到。3.2 在 Qt 里打开加密库最常用的 QSQLCIPHER 写法先把最简单的连接代码贴出来这是 QtCipherSqlitePlugin 最典型的用法demo 工程里也基本是这个结构#include QCoreApplication #include QSqlDatabase #include QSqlQuery #include QSqlError #include QDebug int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QSqlDatabase db QSqlDatabase::addDatabase(QSQLCIPHER); db.setDatabaseName(encrypted.db); db.setUserName(qtcipher); // 占位符不参与认证 db.setPassword(MyStrongPass123); // 真正的加密密钥 if (!db.open()) { qCritical() open failed: db.lastError().text(); return 1; } QSqlQuery query(db); if (!query.exec(CREATE TABLE IF NOT EXISTS t (id INTEGER PRIMARY KEY, v TEXT))) { qWarning() query.lastError().text(); } query.prepare(INSERT INTO t(v) VALUES(?)); query.addBindValue(hello sqlcipher); if (!query.exec()) { qWarning() query.lastError().text(); } query.exec(SELECT * FROM t); while (query.next()) { qDebug() query.value(0).toInt() query.value(1).toString(); } db.close(); return 0; }这段代码做了什么先用addDatabase(QSQLCIPHER)加载插件驱动setDatabaseName指定库文件路径然后setUserName和setPassword分别设置用户名和密码。这里有个容易误解的点userName 字段在 SQLCipher 语义里没有认证作用驱动只是把它当占位符真正的密钥来自setPassword。所以两个字段都要填但决定能不能打开库的是 password。对应的 pro 文件也要记得加 sql 模块QT core sql CONFIG console TARGET qtcipher_demo SOURCES main.cppQT sql是必须的否则QSqlDatabase相关头文件和链接库都找不到。编译运行后如果能看到SELECT查出来的那行数据说明密钥正确、库也建成功了。此时去数据库文件所在的目录看encrypted.db已经不能直接用普通工具打开了。3.3 更灵活的连接方式PRAGMA key、hex 密钥与连接选项setPassword的方式适合大多数场景但有些时候密钥需要在运行时动态拼接或者你想更精确地控制 SQLCipher 参数那就得用 PRAGMA 方式。先看怎么打开连接QSqlDatabase db QSqlDatabase::addDatabase(QSQLCIPHER); db.setDatabaseName(encrypted.db); db.setConnectOptions(QSQLCIPHER_CRYPTO_INIT); if (!db.open()) { qWarning() open failed: db.lastError().text(); return 1; } QSqlQuery q(db); q.exec(PRAGMA key MyStrongPass123); q.exec(CREATE TABLE IF NOT EXISTS t (id INTEGER PRIMARY KEY, v TEXT));setConnectOptions(QSQLCIPHER_CRYPTO_INIT)的作用是告诉驱动这个连接要走加密初始化分支随后执行PRAGMA key ...来设置密钥。这两种方法选一种就行不要同时用否则可能出现密钥被后执行的语句覆盖的情况。PRAGMA 方式还有一个进阶写法是传 hex 格式的原始密钥q.exec(PRAGMA key \x5F4DCC3B5AA765D61D8327DEB882CF99\);x...表示引号里是十六进制原始密钥SQLCipher 会直接把它当密钥字节用而不会按口令走一遍 KDF。这样做的好处是绕开了口令中特殊字符导致的 SQL 语法问题第 5 章会专门讲这个坑。注意 hex 密钥长度要和加密算法匹配AES-256 需要 32 字节也就是 64 个十六进制字符。demo 工程里通常把打开、建表、插入的流程都封装好了业务代码直接抄它模板再改表结构即可不用从零写。4. 验证加密是否真的生效文件头检查与第三方工具实测有的项目装完插件能跑但加密到底生效没有很多人心里没底。我见过有人代码里 set 了 password结果库文件拿 DB Browser 一开还是明文。这章给出一套可执行的验证方法按顺序做一遍加密有没有生效就非常清楚了。4.1 先看文件头明文与加密库在十六进制下的区别普通 SQLite 文件的前 16 个字节是固定的十六进制为53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00对应 ASCII 字符串SQLite format 3。SQLCipher 创建出来的库这个位置是随机密文根本不会有可读的 ASCII 内容。在命令行里对比两个文件xxd -l 32 plain.db xxd -l 32 encrypted.dbWindows 自带 PowerShell 也能做同样的事Format-Hex -Path encrypted.db -Count 32文件位置明文 SQLite 库SQLCipher 加密库第 0-15 字节SQLite format 3\0随机密文无固定特征第 16-31 字节页大小、版本号等元数据随机密文看到前 8 个字节还是S Q L i t e说明加密没生效得回头查代码里是不是真的走了 QSQLCIPHER 驱动或者是不是犯了第 5 章“给已有明文库设置 key”的错误。看到一串不可读的十六进制说明加密流程已经起作用。4.2 第三方工具交叉验证DB Browser、sqlite3 与 SQLCipher 命令行网上经常有人问“sqlite 数据库文件能否加密”“sqlite 文件用什么打开”答案在这个场景里很明确加密后必须用带 SQLCipher 的工具和正确密码才能打开。拿普通工具去读加密库得到的就是一系列的报错。先试普通 sqlite3 命令行sqlite3 encrypted.db回应通常是file is not a database。再用 DB Browser for SQLite 打开这个文件要么直接报无法识别数据库格式要么弹出密码框——这取决于你装的是不是带 SQLCipher 的版本。输错密码同样打不开。这些现象都是加密生效的直接证据。真正的验证要交给 SQLCipher 版命令行sqlite3 encrypted.db PRAGMA key MyStrongPass123; .tables SELECT * FROM t;能正确列出表并查询到数据说明密钥和加密参数都匹配。注意 SQLCipher 4 创建的库用旧版 SQLCipher 命令行可能仍然打不开需要用同代版本这个版本差异在第 5 章专门说。4.3 应用层自检不设密钥连接同一个文件第三方工具验证完再在应用层做一次对照测试把“有没有 key”的差别直接暴露出来QSqlDatabase db QSqlDatabase::addDatabase(QSQLCIPHER, noKeyConn); db.setDatabaseName(encrypted.db); if (!db.open()) { qWarning() 无密钥打开失败: db.lastError().text(); } else { QSqlQuery q(db); q.exec(SELECT count(*) FROM t); if (q.lastError().isValid()) { qWarning() 无密钥查询失败: q.lastError().text(); } }这段程序和第 3.2 节的正向连接形成对照同一个文件、同一个驱动唯一差别是没有设置密码。SQLCipher 有个特性是open阶段不一定会立刻报错真正的密钥校验发生在第一条 SQL 语句执行时不过 QtCipher 的驱动在open内部常会做一次试探查询所以lastError()能当场反映出file is not a database一类的错误。如果这段代码没有任何报错还能查出数据基本可以断定加密没生效回去检查驱动名和密码设置的位置。5. 避坑指南QtCipher 实战中的五个典型问题下面是这个插件在真实项目里最常翻车的五个地方每一条我都按“现象→原因→解决”的顺序写看着像排查手册实际上是多次踩坑换来的血泪经验。5.1 插件装上但 QtCreator 里找不到现象复制了编译好的 dll重启 QtCreator 之后About Plugins 列表里根本没有 QtCipher 或 sqlcipher 相关的条目。原因九成是路径放错了。插件目录是C:\Qt\Qt5.15.2\Tools\QtCreator\lib\qtcreator\plugins有人把它放进了C:\Qt\Qt5.15.2\plugins或 Qt 库目录C:\Qt\Qt5.15.2\5.15.2\msvc2019_64\plugins。QtCreator 只扫描它自己安装目录下的 plugins其他位置放再多也没用。剩余一小部分是 QtCreator 的插件缓存没刷新。解决把 dll 转移到正确路径后重启还不行就删除%APPDATA%\QtProject\qtcreator\cache下的缓存再重启最后打开QtCreator.log看加载日志里面会写清楚是路径找不到还是依赖 dll 缺失。5.2 编译通过但运行时报 QSQLCIPHER driver not loaded现象代码里addDatabase(QSQLCIPHER)QtCreator 编译也没报错但程序一跑就提示QSqlDatabase: QSQLCIPHER driver not loaded。原因插件是给 QtCreator 进程加载的你独立运行编译出来的 exe 时Qt 的插件搜索路径里并没有 sqlitecipher.dll另一个常见原因是插件依赖的 OpenSSL 等 dll 不在 exe 同目录加载失败后被 Qt 静默忽略了。解决最省事的方法是直接从 QtCreator 里运行目标程序让 QtCreator 把插件目录带进进程环境独立发布时在main函数早期设置环境变量QT_PLUGIN_PATH指向插件所在目录或者把插件 dll 和依赖 dll 一起放到 exe 旁边。排查时先在程序里打印QCoreApplication::libraryPaths()看实际搜索路径里有没有插件目录再用 dumpbin 或 Process Explorer 检查依赖项是否齐全。5.3 给已经存在的明文库设置 key数据仍是明文现象拿一个现成的plain.db放进程序设置了 password打开、查询全都正常但用十六进制看文件头还是SQLite format 3DB Browser 也能直接打开看到全部数据。原因SQLCipher 只对“新建的库”和“已是加密格式的库”走加密流程。一个普通 SQLite 文件你给它 key 它也不会回炉重造后续写入的数据照样落到明文文件里。加密必须在建库那一刻就带着 key 创建不是事后给一把钥匙就能补个壳。解决把旧数据迁移进一个新建的加密库。常见做法是用 ATTACH 语法ATTACH DATABASE legacy.db AS plaintext; CREATE TABLE encrypted_users AS SELECT * FROM plaintext.users; DETACH DATABASE plaintext;执行前先确认新库是通过 QSQLCIPHER 驱动创建的加密库再执行上面的语句把plaintext里的表搬到当前加密库。迁移完核对表记录数确认无误后再删旧库。这也是“sqlite 数据库文件能否加密”问题里最常见的误解加密要从建库开始不是中途加个 key 就完事。5.4 密码里带单引号PRAGMA key 语法报错现象密码是abcdef21这样带单引号的字符串执行PRAGMA key abcdef21时报near def21: syntax error库永远打不开。原因SQLite 的字符串字面量用单引号包裹密码里的单引号把 SQL 语句截断了。PRAGMA key本质是一条 SQL同样受语法规则约束。解决先用 SHA-256 把口令算成 hex再用x...格式传入密码里的任何特殊字符都不会再影响 SQL 解析// 假设已经从安全渠道取到口令 QByteArray pass QByteArrayLiteral(abcdef21); QByteArray hash QCryptographicHash::hash(pass, QCryptographicHash::Sha256); QSqlQuery q(db); q.exec(QString(PRAGMA key \x%1\).arg(QString::fromLatin1(hash.toHex())));或者干脆改用setPassword的连接方式让驱动内部处理口令转义不手写 PRAGMA。从这笔经验之后我但凡要手写含密钥的 SQL一律先转 hex省得在特殊字符上栽跟头。5.5 SQLCipher 3 老库在新插件里打不开现象同一个密码老环境能正常打开换到新机器新 QtCipher 版本后报file is not a database。原因SQLCipher 4 把默认的kdf_iter从 64000 改成了 256000HMAC 算法也从 SHA1 换成了 SHA512。老库是按旧参数加密的新驱动按新参数派生密钥和校验数据自然对不上。解决打开老库前先显式指定旧参数再执行迁移命令PRAGMA key oldpass; PRAGMA kdf_iter 64000; PRAGMA cipher_hmac_algorithm HMAC_SHA1; PRAGMA cipher aes-256-cbc; PRAGMA cipher_migrate;cipher_migrate是 SQLCipher 4 提供的升级命令会把库文件重写成新格式。执行前务必先复制一份库文件备份迁移过程如果中途断电或写满磁盘库文件可能损坏。迁移完成后再用默认参数打开就正常了。参数差异对照表见 3.1 节那四行参数是这类问题排查的核心。6. 密码丢失与密钥管理派生、迁移与最后防线密码丢失是 SQLCipher 唯一没有“后悔药”的场景不存在后门也不存在万能钥匙。所以最后一章专门讲怎么管住密钥让前面几章的加密能力真正落地。6.1 口令到密钥的派生用 hex 密钥代替明文口令代码里直接写MyStrongPass123这种明文口令一次源码泄露就把加密废了。常见做法是先把口令经过 PBKDF2 派生再以 hex 形式传入 PRAGMAimport hashlib passphrase bMyStrongPass123 salt bytes.fromhex(A1B2C3D4E5F6A7B8) key hashlib.pbkdf2_hmac(sha256, passphrase, salt, 256000) print(key.hex())连接数据库时执行PRAGMA key x上面输出的hex;代码和日志里都不再出现可读口令salt 要单独固定保存否则换机器后无法重算出同一把密钥。6.2 迁移三件套库文件、密钥参数、一份配置带 SQLite 的项目做机器迁移时别只拷一个 .db 文件。SQLCipher 打开一个库除了密钥本身还需要 cipher、kdf_iter、cipher_page_size 这些参数。建议把参数写进一份 JSON 随库备份{ database: data/encrypted.db, cipher: aes-256-cbc, kdf_iter: 256000, cipher_page_size: 4096, salt: A1B2C3D4E5F6A7B8 }文件本身是密文参数泄露不致命真正的口令单独交给项目负责人保管。迁移时带上库文件加这份配置新环境几分钟就能接上。6.3 密钥不进代码环境变量与系统凭据管理器把密钥硬编码进源码是最容易埋雷的习惯。常见做法是程序启动时从环境变量读取口令比如SQLCIPHER_KEYWindows 下也可以用系统自带的“凭据管理器”保存macOS 用钥匙串Qt 工程里可以用 QtKeychain 这类库封装或者直接用环境变量过度。这样源码仓库即使被拷走密钥也不会一起泄露。把密码写死在代码里的后果往往要到交付现场才暴露客户换服务器、运维接手、代码仓库权限放开哪一环都可能让密钥失控。从那以后我每交付一个带 SQLite 的 Qt 项目交付清单里都强制加两条一条是用 DB Browser 验证加密库确实打不开另一条是把密钥配置单独封存交给负责人。SQLite 加密这件事没有银弹QtCipher 能防住的是“拷走文件直接读”这一类最常见的裸奔风险密钥本身的管理责任始终在开发者自己手里。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

2026最新wordpressthemeforfreegreen实战避坑指南 2026/9/26 22:09:12

2026最新wordpressthemeforfreegreen实战避坑指南

2026最新wordpressthemeforfreegreen实战避坑指南 找建站公司怕被坑高价?这大概是无数站长和创业者深夜里最真实的焦虑。你明明只想做个简单的展示站,报价单却动辄上万,还夹杂着各种看不懂的“功能溢价”。别慌,2026最…

阅读更多 →
Beyond Compare 5企业级落地实践指南 2026/9/26 22:09:06

Beyond Compare 5企业级落地实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
无标定视觉伺服:从图像雅可比矩阵到机器人闭环控制实战 2026/9/26 22:09:06

无标定视觉伺服:从图像雅可比矩阵到机器人闭环控制实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
社区团播系统选型:重建邻里信任的四大生死指标 2026/9/26 22:08:59

社区团播系统选型:重建邻里信任的四大生死指标

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
MES基础业务考核试题解析:ISA-95、BOM与QMS核心考点 2026/9/26 22:08:59

MES基础业务考核试题解析:ISA-95、BOM与QMS核心考点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
DeepSeek-OCR-2批量PDF解析实战:100并发+64线程预处理的高吞吐文档转换完整教程 2026/9/26 22:08:59

DeepSeek-OCR-2批量PDF解析实战:100并发+64线程预处理的高吞吐文档转换完整教程

DeepSeek-OCR-2批量PDF解析实战:100并发64线程预处理的高吞吐文档转换完整教程 【免费下载链接】DeepSeek-OCR-2 Visual Causal Flow 项目地址: https://gitcode.com/gh_mirrors/de/DeepSeek-OCR-2 DeepSeek-OCR-2 是一款基于 Visual Causal Flow&#xff08…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉