PDF 合并别再用在线工具:12 份文件浏览器里合完,实测不上传

举报
deli007 发表于 2026/10/15 23:40:56 2026/10/15
【摘要】 PDF 合并别再用在线工具:12 份文件浏览器里合完,实测不上传

12 个 PDF、240 页,拖进去点一下,33 毫秒合完,输出 3.2 KB。

整个过程没有一次上传。我把下载回来的文件用 pypdf 数了一遍:240 页,文件头还是 %PDF-1.7。

换成 50 个文件、1000 页,耗时 104 毫秒,页面记录到的网络请求仍然是 0 次。

图 1:工具首屏,左侧是文件列表与合并、拆分按钮,右侧是输出结果,顶部两个角标分别是 pdf-lib 加载状态和网络请求计数

在线案例与源码:https://atomgit.com/deli007/demo_park/tree/main/codearts-pdf-merge-tool
生成物只有一个 index.html,合并和拆分都在浏览器内存里完成,文件不出本机。

一、为什么值得自己搭一个:在线工具的麻烦在「先上传」

搜 PDF 合并,前几页的工具流程几乎一样:选文件、等进度条、下载。

进度条那几秒里,你的发票、合同、扫描件已经在别人的服务器上落过盘了。

带客户名单的对账单、身份证扫描件、签了保密协议的附件,很多人根本不敢往这些站点传。

我要的只有一件事:文件在本地算完,页面不负责传。

二、准备环境:进入码道 Web,把需求写成一段话

浏览器打开 https://devcloud.cn-north-4.huaweicloud.com/chat/home ,登录后把需求写进对话框,就能拿到一个能跑的单文件应用。

不用装软件,不用配环境,本文这个工具就是这么来的。

码道有三种使用方式:WebUI(浏览器对话)、TUI(终端命令行)和桌面 IDE(IDE 插件)。本文用 WebUI 版演示。

需求我写了 10 条,事后看最值钱的是这三条:

  • 页面上要有网络请求计数,从打开页面到合并结束,这个数必须一直是 0;
  • 遇到损坏文件和加密文件,要在那一行和顶部状态栏写清原因,不许只打控制台日志;
  • 页面里要有自检面板,每条断言把期望值和实测值都渲染出来。

第三条是这次没翻车的直接原因,后面细说。

三、实测:12 个文件、240 页、33 毫秒

我拿 12 个各 20 页的 PDF 拖进页面,列表里 12 行,页数一栏自动读出每份 20 页。

点一下「合并全部」,右侧输出面板给出三个数:240 页、3.2 KB、33 毫秒。

图 2:12 个文件合并后的输出面板,页数、输出体积、耗时三个数字并排显示,下面是下载按钮

页数是 12 乘 20,对得上;体积比单个文件还小,因为输出里没有重复的字体和页对象,只有页面树。

这 33 毫秒不是估算,是页面里 performance.now() 卡出来的两端差值。

四、文件越多越慢吗:3 到 50 个文件的对照

我把同样的测试跑成了四档,输入文件都是 20 页一份。

输入文件数 输入总页数 输出页数 输出体积 合并耗时
3(页面内置示例) 12 12 5.2 KB 1.5 毫秒
12 240 240 3.2 KB 33 毫秒
20 400 400 5.3 KB 45.7 毫秒
50 1000 1000 12.4 KB 104.3 毫秒

从 240 页到 1000 页,页数翻了 4 倍多,耗时从 33 毫秒涨到 104 毫秒,是 3 倍出头,接近线性。

真正撑住速度的是页数少:合并只是在页面树上搬引用,不重新渲染内容。

所以这组数字要带着前提看:我的测试文件是空白页,一页不到 3 KB;换成扫描件,体积和耗时都会明显上去。

五、把合并结果下载回来,用 pypdf 数页数

页面自己说 240 页,我不太想直接信,就把下载按钮产出的那份文件截下来,交给 Python 侧的 pypdf 复核。

三次复核的结果:12 页那次是 5333 字节,240 页那次是 3300 字节,1000 页那次是 12729 字节。

三次读出来的页数分别是 12、240、1000,和页面报的数字一致,文件头都是 %PDF-1.7。

这也是我判断「它真的合成了 PDF」而不是「它在页面上画了个数字」的办法。

六、拆分:抽 5 到 9 页和第 12 页,出来 6 页

选中一个 20 页的文件,在页码框里写 5-9,12,点「拆分 / 提取」。

输出面板报 6 页、0.6 KB、2.5 毫秒,我用 pypdf 数这份新文件,确实是 6 页。

图 3:左边第二个文件被选中,页码框里写着 1-3,右侧给出提取结果的页数、体积和耗时

页码写错它也认得出:填 9-2,状态栏直接给「起始页 9 大于结束页 2」,不生成文件。

序号不连续的写法是逗号隔开,1-3,5 这种能一次抽两段出来。

七、三种坏文件,页面各说各的

失败路径我专门造了三个文件试:一个把正常 PDF 拦腰截断,一个用密码加密过,一个干脆是文本文件改名成 .pdf。

三个都在列表里单独标红,各给自己的一句话:

输入 页面给出的原因
被截断的 PDF 无法解析:文件损坏或不是有效 PDF
密码保护的 PDF 无法解析:PDF 已加密或受密码保护
文本文件改名为 .pdf 无法解析:文件损坏或不是有效 PDF

加密那个文件的判别是页内的,pdf-lib 解密时报的关键词里带 password,页面据此给出加密提示,不是按文件名猜的。

图 4:三个坏文件同时拖进去,每一行标红并给出原因,顶部状态栏同步显示最后一条错误

顶部的「合并全部」会跟着置灰,不让带着坏文件往下走。

八、页面自带 5 条断言,页数对不上就会红

底部有一块自检面板,点「运行自检」现场生成示例文件,再跑合并和拆分,把每一步的期望值和实测值并排打出来。

5 条断言,当前是 5/5 通过,自检耗时 7.5 毫秒,末尾一行还写着自检全程外发网络请求 0 次。

图 5:自检面板展开,5 条断言逐条给出期望值与实测值,最后一行是 5/5 通过

我把这 5 条抄下来:示例文件页数合计 12;合并后 12 页;提取第 2 页得到 1 页;提取 1-3 页得到 3 页;非法页码 9-2 被拦下。

这 5 条的共同点是把数字写死在期望值里,实测值来自真实解析结果,错了就红,藏不住。

九、说点不足

输出的 PDF 不做压缩,扫描件合出来的体积基本等于输入之和。

加密文件只能报错,不给输密码解锁,pdf-lib 本身不带解密能力。

文件顺序要手动拖,页面不会按文件名或者修改时间自动排。

而且它不联网就是残缺的:pdf-lib 从 CDN 加载,断网打开只会看到「加载失败」,按钮全灰。

我故意没让它在这种情况下假装还能用。

十、实测数据汇总

项目 实测值 说明
单个 HTML 文件体积 30219 字节 30 KB 左右,无构建步骤
12 个文件合并 33 毫秒 / 240 页 输出 3.2 KB
50 个文件合并 104.3 毫秒 / 1000 页 输出 12.4 KB
拆分 5-9,12 页 2.5 毫秒 / 6 页 输出 624 字节
合并结果复核 12 / 240 / 1000 页 下载后用 pypdf 数出来的
自检断言 5 / 5 通过 自检耗时 7.5 毫秒
页面资源请求 1 条 只有 pdf-lib 的 CDN 脚本
携带文件内容的请求 0 次 页面自记计数与资源列表都能对上

十一、本地复现

生成物只有一个 index.html,双击就能打开,第一次打开需要联网拉 pdf-lib。

也可以起个静态服务看:python -m http.server 8000,然后访问 http://localhost:8000 。

想自己造测试文件,用 pypdf 几句就能生成一叠空白页 PDF,我这轮的输入文件就是这么来的。

下载回来的成品想复核页数,也交给 pypdf:读一遍 len(reader.pages),和页面报的数对一下。

想看它有没有偷偷上传,按 F12 打开网络面板,再点一次合并,里面不会多出任何请求。

十二、用码道做这个小工具的体会

这次最值钱的一条需求是「页面里要有自检面板,把期望值和实测值都渲染出来」。

收到页面我第一件事就是点运行自检,5 条断言全绿,示例文件的页数、合并后的页数、非法页码的拦截都在里面。

但这只能证明页面自己算得对,能不能信还得看外面:所以我把合并结果下载回来,用 pypdf 再数一遍页数。

第三条心得是需求里把验收数字写死,比如直接写着「50 个文件、1000 页要能合完」,交回来的东西好不好判断,一眼就有答案。

失败路径也一样,我在需求里写明「库加载失败就置灰按钮、挂红条」,验证时把 CDN 地址换成连不上的域名再打开,红条、按钮全灰,和需求对得上。

不足的地方也说一句:这个工具只覆盖合并和按页提取,页面里没有压缩、没有水印、也没有加密解密,这几类需求它一个都接不住。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。