在日常开发中,从 Word 文档中提取表格数据是一个高频需求------无论是数据导入、报表迁移,还是将合同中的结构化信息入库。手动复制粘贴效率低下,调用 Office COM 组件又面临环境依赖和版本兼容问题。本文介绍一种轻量方案:使用 Free Spire.Doc for .NET 在 C# 中读取 Word 表格数据。
说明:Free Spire.Doc 是 Spire.Doc 的免费社区版,无需安装 Microsoft Word,支持 .doc 和 .docx 格式的读写。安装方式:
Install-Package FreeSpire.Doc。
核心对象模型
Free Spire.Doc 解析 Word 表格时,文档的层级结构如下:
| 对象 | 对应结构 | 获取方式 |
|---|---|---|
Document |
整个 Word 文档 | new Document() + LoadFromFile() |
Section |
文档中的"节" | doc.Sections[i] |
Table |
表格 | section.Tables[i] |
TableRow |
表格行 | table.Rows[i] |
TableCell |
单元格 | row.Cells[i] |
Paragraph |
单元格内的段落 | cell.Paragraphs[i] |
核心遍历路径是:Document → Section → Table → Row → Cell → Paragraph。一个文档可以包含多个节,每个节可以包含多个表格。
基础读取代码
以下代码读取 Word 文档中所有表格的数据,输出到控制台:
csharp
using Spire.Doc;
using System;
namespace ReadWordTable
{
class Program
{
static void Main(string[] args)
{
Document doc = new Document();
doc.LoadFromFile(@"E:\sample.docx");
foreach (Section section in doc.Sections)
{
foreach (Table table in section.Tables)
{
Console.WriteLine("=== 表格开始 ===");
foreach (TableRow row in table.Rows)
{
foreach (TableCell cell in row.Cells)
{
string cellText = cell.Paragraphs[0].Text.Trim();
Console.Write(cellText + "\t");
}
Console.WriteLine();
}
}
}
doc.Close();
}
}
}
这段代码的逻辑是:加载文档后,依次遍历每个节的每个表格,再逐行逐单元格提取文本,用制表符分隔单元格、换行符分隔行。
几个容易被忽略的细节
单元格包含多个段落时只取第一段会丢数据。 Word 表格的一个单元格内可能有多个段落(例如多行说明文字)。上面的基础代码只读取了 Paragraphs[0],如果单元格内容较多,会遗漏后续段落。更稳妥的做法是遍历所有段落:
csharp
string cellText = "";
for (int i = 0; i < cell.Paragraphs.Count; i++)
{
cellText += cell.Paragraphs[i].Text.Trim() + " ";
}
cellText = cellText.Trim();
合并单元格在遍历时会出现重复内容。 当表格中存在水平或垂直合并的单元格时,TableRow.Cells 的索引可能对应到同一个逻辑单元格对象。遍历时如果直接按索引读取,合并区域的数据会被重复提取。实践中需要根据业务需求判断是否对合并单元格做去重处理,或者使用库提供的合并信息判断方法。
嵌套表格需要递归处理。 如果单元格内嵌入了另一个表格,上面的遍历不会进入嵌套表格。此时需要检查 cell.ChildObjects,找出其中类型为 Table 的对象并递归遍历。
提取到文本文件的完整写法
将每个表格保存为独立的文本文件,单元格用制表符分隔,行用换行符分隔,可以直接粘贴到 Excel 中:
csharp
using Spire.Doc;
using Spire.Doc.Collections;
using System.IO;
using System.Text;
namespace ExtractWordTable
{
internal class Program
{
static void Main(string[] args)
{
Document doc = new Document();
doc.LoadFromFile("表格.docx");
for (int sectionIndex = 0; sectionIndex < doc.Sections.Count; sectionIndex++)
{
Section section = doc.Sections[sectionIndex];
TableCollection tables = section.Tables;
for (int tableIndex = 0; tableIndex < tables.Count; tableIndex++)
{
ITable table = tables[tableIndex];
string tableData = "";
for (int rowIndex = 0; rowIndex < table.Rows.Count; rowIndex++)
{
TableRow row = table.Rows[rowIndex];
for (int cellIndex = 0; cellIndex < row.Cells.Count; cellIndex++)
{
TableCell cell = row.Cells[cellIndex];
string cellText = "";
for (int paraIndex = 0; paraIndex < cell.Paragraphs.Count; paraIndex++)
{
cellText += cell.Paragraphs[paraIndex].Text.Trim() + " ";
}
tableData += cellText.Trim();
if (cellIndex < row.Cells.Count - 1)
tableData += "\t";
}
tableData += "\n";
}
string filePath = Path.Combine(
"Tables",
$"Section{sectionIndex + 1}_Table{tableIndex + 1}.txt");
Directory.CreateDirectory("Tables");
File.WriteAllText(filePath, tableData, Encoding.UTF8);
}
}
doc.Close();
}
}
}
这份代码将每个表格保存为 Tables/Section1_Table1.txt 等文件,单元格间用 \t 分隔,行末用 \n 结束,输出格式兼容 Excel 的直接粘贴。
免费版限制提醒
Free Spire.Doc 免费版在读取文档时存在硬性限制:单个文档最多处理 500 个段落和 25 个表格。该限制在读取文件时即被强制执行,超出部分的表格数据不会被加载。
对于大多数中小型场景------比如从合同模板、配置表、简单的数据报表中提取表格------25 个表格的上限通常够用。建议在正式集成前先确认目标文档的实际表格数量。