Java 提供了多种方式处理 Word 文档拆分操作,可以根据不同需求选择合适的拆分依据:按页拆分能够保留文档的页面布局,按分页符拆分适用于人工设置的内容分隔,而按分节符拆分则更适合处理具有章节结构的复杂文档。
本文将介绍如何使用 Java 实现 Word 文档的按页拆分、按分页符拆分以及按分节符拆分,帮助开发者根据实际业务需求灵活处理 Word 文件。
环境设置
要运行下面的代码示例,需要先在 Java 项目 中添加 Word 文档处理所需的依赖。
如果使用 Maven,可以在 pom.xml 中加入:
<span><<span>repositories</span>></span>
<span><<span>repository</span>></span>
<span><<span>id</span>></span>com.e-iceblue<span></<span>id</span>></span>
<span><<span>name</span>></span>e-iceblue<span></<span>name</span>></span>
<span><<span>url</span>></span>https://repo.e-iceblue.cn/repository/maven-public/<span></<span>url</span>></span>
<span></<span>repository</span>></span>
<span></<span>repositories</span>></span>
<span><<span>dependencies</span>></span>
<span><<span>dependency</span>></span>
<span><<span>groupId</span>></span>e-iceblue<span></<span>groupId</span>></span>
<span><<span>artifactId</span>></span>spire.doc<span></<span>artifactId</span>></span>
<span><<span>version</span>></span>14.8.4<span></<span>version</span>></span>
<span></<span>dependency</span>></span>
<span></<span>dependencies</span>></span>
- 将 Word 文档的每一页拆分为单独文件
如果需要按照 Word 实际排版后的页面进行拆分,可以使用 Document.extractPages() 方法从原文档中提取页面,并生成新的 Document 对象。
下面的示例获取 Word 文档的总页数,然后逐页提取并保存为独立的 DOCX 文件:
<span>import</span> com.<span>spire</span>.<span>doc</span>.<span>Document</span>;
<span>import</span> com.<span>spire</span>.<span>doc</span>.<span>FileFormat</span>;
<span>public</span> <span>class</span> <span>SplitWordByPage</span> {
<span>public</span> <span>static</span> <span>void</span> <span>main</span>(<span><span>String</span>[] args</span>) {
<span>// Load the Word document</span>
<span>Document</span> <span>document</span> = <span>new</span> <span>Document</span>();
<span>document</span>.<span>loadFromFile</span>(<span>"Sample.docx"</span>);
<span>// Get the total number of pages</span>
int pageCount = <span>document</span>.<span>getPageCount</span>();
<span>// Extract each page to a separate document</span>
<span>for</span> (int i = <span>0</span>; i < pageCount; i++) {
<span>Document</span> pageDocument = <span>document</span>.<span>extractPages</span>(i, <span>1</span>);
pageDocument.<span>saveToFile</span>(
<span>"output/Page-"</span> + (i + <span>1</span>) + <span>".docx"</span>,
<span>FileFormat</span>.<span>Docx</span>
);
pageDocument.<span>close</span>();
}
<span>document</span>.<span>close</span>();
}
}
例如,一个包含 5 页的 Word 文档会被拆分为:
Page-1.docx
Page-2.docx
Page-3.docx
Page-4.docx
Page-5.docx
extractPages() 的第一个参数表示起始页面索引,从 0 开始;第二个参数表示需要提取的页面数量。因此:
document<span>.extractPages</span>(<span>i</span>, <span>1</span>);
表示从索引 i 开始提取 1 页。
- 提取 Word 文档中的指定页码范围
extractPages() 也可以一次提取连续的多个页面。
例如,需要将原文档的第 3 页到第 6 页保存为一个新的 Word 文档,可以使用下面的代码:
<span>import</span> com.<span>spire</span>.<span>doc</span>.<span>Document</span>;
<span>import</span> com.<span>spire</span>.<span>doc</span>.<span>FileFormat</span>;
<span>public</span> <span>class</span> <span>ExtractWordPageRange</span> {
<span>public</span> <span>static</span> <span>void</span> <span>main</span>(<span><span>String</span>[] args</span>) {
<span>// Load the Word document</span>
<span>Document</span> <span>document</span> = <span>new</span> <span>Document</span>();
<span>document</span>.<span>loadFromFile</span>(<span>"Sample.docx"</span>);
int startPage = <span>3</span>;
int endPage = <span>6</span>;
<span>// Validate the page range</span>
<span>if</span> (startPage < <span>1</span>
|| endPage < startPage
|| endPage > <span>document</span>.<span>getPageCount</span>()) {
<span>throw</span> <span>new</span> <span>IllegalArgumentException</span>(<span>"Invalid page range."</span>);
}
<span>// Convert the page number to a zero-based index</span>
int startIndex = startPage - <span>1</span>;
<span>// Calculate the number of pages to extract</span>
int pageCount = endPage - startPage + <span>1</span>;
<span>// Extract the specified pages</span>
<span>Document</span> extractedDocument =
<span>document</span>.<span>extractPages</span>(startIndex, pageCount);
extractedDocument.<span>saveToFile</span>(
<span>"output/Pages-3-6.docx"</span>,
<span>FileFormat</span>.<span>Docx</span>
);
extractedDocument.<span>close</span>();
<span>document</span>.<span>close</span>();
}
}
需要注意的是,extractPages() 使用从 0 开始的页面索引,而且第二个参数是提取页数,不是结束页码。
因此,提取第 3 页到第 6 页时实际调用的是:
document.extractPages(2, 4)<span>;</span>
- 按分页符拆分 Word 文档
分页符通常用于强制后续内容从新的一页开始。在 Word 中通过 Ctrl + Enter 插入的分页符属于显式分页符。
如果希望根据这些分页符拆分文档,可以遍历段落中的 Break 对象,并通过 BreakType.Page_Break 判断是否遇到了分页符。
下面的示例在检测到分页符时结束当前文档,并将后续内容写入新的 Word 文件:
import com<span>.spire</span><span>.doc</span>.*;
import com<span>.spire</span><span>.doc</span><span>.documents</span>.*;
public class SplitWordByPageBreak {
public static void <span>main</span>(String[] args) {
<span>// Load the source document</span>
Document source = new <span>Document</span>();
source<span>.loadFromFile</span>("Sample.docx");
<span>// Create the first output document</span>
Document partDocument = <span>createDocument</span>(source);
<span>Section</span> targetSection = partDocument<span>.getSections</span>()<span>.get</span>(<span>0</span>);
int fileIndex = <span>1</span>;
<span>// Traverse all sections</span>
for (int s = <span>0</span>; s < source.getSections()<span>.getCount</span>(); s++) {
<span>Section</span> sourceSection = source<span>.getSections</span>()<span>.get</span>(s);
<span>// Copy section properties</span>
sourceSection<span>.cloneSectionPropertiesTo</span>(targetSection);
<span>// Traverse paragraphs and tables</span>
for (int i = <span>0</span>;
i < sourceSection.getBody()<span>.getChildObjects</span>()<span>.getCount</span>();
<span>i</span>++) {
DocumentObject <span>object</span> =
sourceSection<span>.getBody</span>()
<span>.getChildObjects</span>()
<span>.get</span>(i);
if (object instanceof Table) {
targetSection<span>.getBody</span>()
<span>.getChildObjects</span>()
<span>.add</span>(object.deepClone());
} else if (object instanceof Paragraph) {
Paragraph paragraph = (Paragraph) <span>object</span>;
targetSection<span>.getBody</span>()
<span>.getChildObjects</span>()
<span>.add</span>(paragraph.deepClone());
<span>// Check for page breaks</span>
for (int j = <span>0</span>;
j < paragraph.getChildObjects()<span>.getCount</span>();
j++) {
DocumentObject child =
paragraph<span>.getChildObjects</span>()<span>.get</span>(j);
if (child instanceof Break
&& ((Break) child)<span>.getBreakType</span>()
<span>.equals</span>(BreakType.Page_Break)) {
int breakIndex =
paragraph<span>.getChildObjects</span>()
<span>.indexOf</span>(child);
<span>// Remove the page break from the current output</span>
Paragraph outputParagraph =
targetSection<span>.getBody</span>()
<span>.getLastParagraph</span>();
outputParagraph<span>.getChildObjects</span>()
<span>.removeAt</span>(breakIndex);
<span>// Save the current part</span>
partDocument<span>.saveToFile</span>(
"output/Part-" + fileIndex + ".docx",
FileFormat.Docx
);
partDocument<span>.close</span>();
fileIndex++;
<span>// Create the next document</span>
partDocument = <span>createDocument</span>(source);
targetSection =
partDocument<span>.getSections</span>()<span>.get</span>(<span>0</span>);
sourceSection<span>.cloneSectionPropertiesTo</span>(
targetSection
);
<span>// Copy the paragraph after the page break</span>
targetSection<span>.getBody</span>()
<span>.getChildObjects</span>()
<span>.add</span>(paragraph.deepClone());
Paragraph firstParagraph =
targetSection<span>.getParagraphs</span>()<span>.get</span>(<span>0</span>);
<span>// Remove the page break and content before it</span>
while (breakIndex >= <span>0</span>
&& firstParagraph.getChildObjects()
<span>.getCount</span>() > <span>0</span>) {
firstParagraph<span>.getChildObjects</span>()
<span>.removeAt</span>(breakIndex);
breakIndex--;
}
if (firstParagraph.getChildObjects()
<span>.getCount</span>() == <span>0</span>) {
targetSection<span>.getBody</span>()
<span>.getChildObjects</span>()
<span>.remove</span>(firstParagraph);
}
}
}
}
}
}
<span>// Save the last part</span>
partDocument<span>.saveToFile</span>(
"output/Part-" + fileIndex + ".docx",
FileFormat.Docx
);
partDocument<span>.close</span>();
source<span>.close</span>();
}
private static Document <span>createDocument</span>(Document source) {
Document document = new <span>Document</span>();
source<span>.cloneDefaultStyleTo</span>(document);
source<span>.cloneThemesTo</span>(document);
source<span>.cloneCompatibilityTo</span>(document);
document<span>.addSection</span>();
return document;
}
}
如果原文档中包含两个分页符,拆分后会得到:
Part-1.docx
Part-2.docx
Part-3.docx
这里识别的是文档中实际存在的 Page Break。文字因页面空间不足而自动流到下一页并不属于分页符,因此不会触发拆分。
如果需要按照 Word 最终显示的每一页拆分文档,应使用前面的 extractPages() 方法。
- 按分节符拆分 Word 文档
Word 中的分节符会将文档划分为多个 Section。不同 Section 可以具有独立的页面尺寸、页边距、页眉页脚和页面方向等设置。
在 Spire.Doc for Java 中,可以直接遍历 Document.getSections(),将每个 Section 克隆到新的 Word 文档中。
<span>import</span> com.<span>spire</span>.<span>doc</span>.<span>Document</span>;
<span>import</span> com.<span>spire</span>.<span>doc</span>.<span>FileFormat</span>;
<span>import</span> com.<span>spire</span>.<span>doc</span>.<span>Section</span>;
<span>public</span> <span>class</span> <span>SplitWordBySectionBreak</span> {
<span>public</span> <span>static</span> <span>void</span> <span>main</span>(<span><span>String</span>[] args</span>) {
<span>// Load the Word document</span>
<span>Document</span> <span>document</span> = <span>new</span> <span>Document</span>();
<span>document</span>.<span>loadFromFile</span>(<span>"Sample.docx"</span>);
<span>// Traverse all sections</span>
<span>for</span> (int i = <span>0</span>;
i < <span>document</span>.<span>getSections</span>().<span>getCount</span>();
i++) {
<span>Section</span> sourceSection =
<span>document</span>.<span>getSections</span>().<span>get</span>(i);
<span>// Create a new document</span>
<span>Document</span> sectionDocument = <span>new</span> <span>Document</span>();
<span>// Preserve document-level styles and settings</span>
<span>document</span>.<span>cloneDefaultStyleTo</span>(sectionDocument);
<span>document</span>.<span>cloneThemesTo</span>(sectionDocument);
<span>document</span>.<span>cloneCompatibilityTo</span>(sectionDocument);
<span>// Clone the current section</span>
sectionDocument.<span>getSections</span>()
.<span>add</span>(sourceSection.<span>deepClone</span>());
<span>// Save it as a separate Word file</span>
sectionDocument.<span>saveToFile</span>(
<span>"output/Section-"</span> + (i + <span>1</span>) + <span>".docx"</span>,
<span>FileFormat</span>.<span>Docx</span>
);
sectionDocument.<span>close</span>();
}
<span>document</span>.<span>close</span>();
}
}
如果原始文档包含三个 Section,拆分后会得到:
<span>Section</span>-<span>1</span><span>.docx</span>
<span>Section</span>-<span>2</span><span>.docx</span>
<span>Section</span>-<span>3</span><span>.docx</span>
一个 Section 可以包含一页,也可以包含多页。因此,按分节符拆分并不等同于按页拆分,而是保留每个 Section 中包含的全部内容。
Word 文档拆分方式对比
| 拆分方式 | 拆分依据 | 核心实现 |
|---|---|---|
| 每页拆分 | Word 实际页面 | `extractPages(i, 1)` |
| 指定页码范围 | 连续的实际页面 | `extractPages(index, count)` |
| 按分页符拆分 | 显式分页符 | `BreakType.Page_Break` |
| 按分节符拆分 | Word Section | `Section.deepClone()` |
如果需要根据 Word 最终排版结果拆分页面,可以使用 extractPages();如果文档已经通过分页符或分节符划分内容,则可以直接按照相应的文档结构进行拆分。
三种拆分方式覆盖多数文档处理场景,明确的索引与页数说明能避免常见误区,适合需要批量拆分 Word 的 Java 开发者参考。