若要在 Python 中依大小分割 PDF,可將連續頁面附加到 PdfWriter,把每個候選項目序列化到位元緩衝區,測量實際產生的位元組數量,然後在下一頁會使該部分超過選定的 MiB 目標之前,先將其定稿。決策必須根據候選 PDF 的實際輸出大小,而非根據來源檔案的比例估算,因為複製的頁面會帶有不同的字型、影像與中繼資料,每次重新組合時都會以不同方式序列化。單純的平均分配猜測(例如將來源位元組數除以頁數)通常會產生超出上限,或讓最後一個部分幾乎為空。採用「測量位元組數」的方法,正符合一個謹慎的無程式碼工具的作法:將頁面順序視為不可中斷的規則,只在頁面邊界開始新部分,並標記任何單獨已超過目標的頁面。同樣的演算法可在 Split PDF by Size 中完全於瀏覽器內執行,因此不論你自行在 Python 中撰寫迴圈,或將來源 PDF 貼到本機工具,結果都完全相同。

split pdf by size python
Split PDF by Size in Python Without Uploading It

What Splitting a PDF by Size Actually Measures

PDF 並非平面的位元組串流。每一頁都是物件的集合:文字、向量路徑、嵌入的影像、字型、色彩描述檔,以及中繼資料。當你將一頁從某個文件複製到另一個文件時,新文件會重建交互參照表並重新序列化物件串流,因此最終的檔案大小取決於目的端的結構,而非該來源頁面在原始文件中所佔的空間。頁面之間共用資源的情況很常見——同一個字型字典、同一個影像 XObject——但一旦這些頁面被分割到不同的檔案中,這些資源就可能被複製兩次,或以不同的方式重新壓縮。PDF 的資源共享,也是為什麼單獨取出的一頁,可能比同一頁與使用相同字型的兄弟頁面並排時還要大的原因之一。因此,任何依大小分割的方式,都必須重新序列化候選頁面並讀取其實際位元組長度,而非進行估算。

當規劃器決定兩個部分之間的邊界時,有三個量是關鍵:設定的目標值、包含下一頁的候選項目位元組長度,以及不含下一頁的目前群組位元組長度。規劃器只有在候選項目維持在目標值或以下時,才會將下一頁納入目前群組。當候選項目會跨越目標值時,規劃器會將目前群組定稿為一個部分,並以被拒絕的頁面作為新部分的第一個成員,重新開始。目標值以 MiB 表示,其中 1 MiB 等於 1,048,576 位元組,工具接受到小數點後三位的小數輸入。最小值 0.01 MiB 的存在,是為了讓確定性的測試能夠在小型文件上強制產生多部分分割;最大值 25 MiB 則符合該工具受限的本機檔案工作流程。

Python Approach: Split a PDF by Size With pypdf

最直接的 Python 路線是 pypdf,它提供 PdfReader 來讀取來源文件,並提供 PdfWriter 來建立新文件。每個候選部分都是全新的 PdfWriter,大小檢查是透過將候選項目寫入記憶體中的 BytesIO 緩衝區,並讀取 len(buf.getvalue()) 來執行,而非向 writer 物件要求估算值。該迴圈是貪婪式的:它會嘗試一次一頁地擴充目前的部分,只有在下一頁會使候選項目超過目標值時,才會將其定稿。已經超過目標值的單一頁面會保留在它自己的部分中,確保沒有任何頁面會被悄悄遺失。

整個流程簡短到可以用文字概述。匯入 pypdf、BytesIO 與 os,然後將 MAX_BYTES 設為以位元組表示的目標值(將 MiB 目標值乘以 1,048,576)。使用 os.makedirs 建立 OUT_DIR。以 reader = PdfReader('input.pdf') 開啟來源檔,並以一個空的 current = PdfWriter() 作為起始,part_index 從 0 開始。定義輔助函式 candidate_byte_length(writer, page),將現有 writer 的頁面與新頁面複製到探測用的 PdfWriter,寫入 BytesIO,並回傳緩衝區的長度。逐頁走訪 reader.pages。若 current 已經有頁面,且包含下一頁的候選項目長度大於 MAX_BYTES,則將 current 寫入 part_{part_index:03d}.pdf,遞增 part_index,並重設 current = PdfWriter()。迴圈結束後,若尾端的 current 仍包含頁面,則將其寫入下一個編號的檔案。MAX_BYTES 與 OUT_DIR 是處理不同文件時唯一需要更改的值。

若要將人類可讀的 MiB 目標值轉換為比較時使用的位元組數值,請將目標值乘以 1,048,576。若目標值為 2.5 MiB,計算方式為 2.5 × 1,048,576 = 2,621,440 位元組。在該目標值生效的情況下,規劃器會接受序列化位元組長度小於或等於 2,621,440 位元組的候選項目,並拒絕超過此值的候選項目。在一次實際觀察的執行中,第 1 至第 4 頁序列化後為 1,820,000 位元組——遠低於上限;而包含第 5 頁的候選項目則達到 2,950,000 位元組,大於 2,621,440,因此第 1 至第 4 頁成為第一部分,第 5 頁則開始第二部分。這個具體的單一序列就完整捕捉了整個決策規則,無需反覆運算。

在迴圈旁邊還應加入兩個實用的細節。第一,若僅包含新頁面的候選項目就已超過目標值,該頁面仍必須以其獨立部分寫入並清楚標示,因為若 Python 迴圈嘗試較小的子群組,會造成無窮迴圈或悄悄略過該頁面。第二,目標值的單位是 MiB 而非 MB:1 MB 是 1,000,000 位元組,1 MiB 是 1,048,576 位元組,混淆兩者會使分割邊界在一般部分上偏移約五個百分點。

How to Split a PDF by Size in Your Browser

若維護 Python 環境的負擔超過任務本身所需,相同演算法的瀏覽器版本可作為 Split PDF by Size 取得。整個工作——頁面複製、序列化、位元組測量、下載產生——皆在目前分頁中本機執行。該頁面絕不會將來源檔案或產生的部分傳送至遠端伺服器,因此對於不能離開裝置的文件而言,此工作流程是安全的。

  1. Choose a non-empty PDF no larger than 25 MiB from your local file system.
  2. Enter the maximum generated size per part as a decimal MiB value between 0.01 and 25, with up to three decimal places.
  3. Run the split, then review the summary for any single page that was kept in its own part because it already exceeded the target.
  4. Download each numbered part. Changing the source file or the size target invalidates earlier download URLs so an old result cannot be confused with the current settings.

Files that are empty, larger than 25 MiB, encrypted, damaged, mislabeled, or unsupported produce a visible error and do not produce any output. Password protection is not bypassed: the tool does not try to decrypt the file, so removing a password before splitting is a separate workflow.

How the Measured-Bytes Planner Reaches a Decision

Both the Python loop and the browser tool use the same three-step decision per page: serialize the candidate that includes the next page, read the candidate's byte length, and compare it to the target. If the candidate fits, the page joins the current group. If the candidate would overshoot, the current group is finalized and the rejected page begins a new group. The greedy choice is deliberate: a backtracking planner that previews every possible split boundary could in theory pack parts more tightly, but it would also be slower, harder to explain, and would still face the same single-page exception.

Page order is treated as unbreakable, which means the tool never reorders pages, never skips a page, and never duplicates a page. The sum of the page counts shown across all generated parts therefore equals the structural page count of the source PDF. The underlying page-copy and save operations are exposed by the pdf-lib PDFDocument.copyPages API and the PDFDocument.save API, which the browser tool uses to perform the same copying and serialization steps that the Python sketch performs with pypdf.

Limits, Edge Cases, and What Survives the Split

The split workflow is bounded on both ends. The source document must be at most 25 MiB and non-empty, and the per-part target must sit between 0.01 and 25 MiB. Outside those ranges the tool reports a visible error rather than producing a partial result. A target that is too small for the largest page in the document will trigger the single-page exception: that page is kept in its own part, the part is flagged as exceeding the target, and the user is told to choose a larger target or to compress the source first. The decision to keep the oversized page rather than retry prevents silent page loss and prevents an infinite retry loop.

Each output is a fresh PDF built by copying the selected source pages into a new document. Page boxes, rotation, vector artwork, text, and embedded raster content are retained to the extent supported by the copy operation. Advanced document-level structures such as bookmarks, scripts, attachments, portfolio relationships, named destinations, and cross-part links may not preserve their original semantics once pages are separated, so interactive forms and navigation-heavy documents should be inspected before the parts are circulated. If a downstream system rejects an oversized single-page part, the right next step is a compression pass rather than a smaller split target.

Python 與本機瀏覽器工具

這兩種方法解決相同的問題,但在設定、控制權和可重現性上有所不同。下表針對您在為特定文件做選擇時所關心的各個面向進行比較。

面向 使用 pypdf 的 Python 迴圈 Split PDF by Size(瀏覽器)
執行位置 您的本機 Python 環境 目前的瀏覽器分頁
網路上傳 無,除非您的腳本將檔案外傳 無 — 頁面、序列化與下載皆留在分頁內
設定成本 安裝 pypdf、撰寫並測試迴圈、選擇輸出目錄 開啟頁面並挑選檔案
大小判定 透過 BytesIO 取得序列化候選位元組長度 透過 pdf-lib save 取得序列化候選位元組長度
單一過大的頁面 若腳本遵循相同規則,會保留為獨立的一部分 會保留為獨立的一部分並明確標示
來源大小上限 僅受您的腳本與磁碟容量限制 25 MiB,強制執行
頁面順序 只要依來源順序附加頁面即可保留 作為不可打破的規則保留
最佳適用情境 可重複的批次作業、CI 流程、自訂輸出命名 臨時性的分割、機敏文件、無程式碼的工作流程

當分割屬於更大流程的一部分、當您希望將邊界邏輯納入版本控制,或當您需要自訂輸出命名方式時,請選擇 Python。當文件不能離開裝置、當您不想維護 Python 環境,或當您需要快速分割並清楚以視覺方式呈現哪些部分(若有的話)超出目標時,請選擇瀏覽器工具。若想更深入了解以位元組數為依據的設計,關於以 MiB 為目標與頁面邊界分割 PDF的指南會從不同角度介紹相同的演算法。

延伸閱讀:如何在不使用 Acrobat 的情況下將 PDF 頁面一分為二。