65.9K
CodeProject 正在变化。 阅读更多。
Home

如何读写ODF/ODS文件 (OpenDocument电子表格)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

5.00/5 (119投票s)

2009年7月24日

CPOL

6分钟阅读

viewsIcon

221917

downloadIcon

7531

本文将介绍ODF格式的基础知识,特别是其在电子表格应用程序(OpenOffice.org Calc和Microsoft Office Excel 2007 SP2)中的实现。文章展示了一个将表格数据写入/读取到.ods文件的演示应用程序。

引言

OpenDocument格式(ODF)是一种基于XML的文件格式,用于表示电子文档,如电子表格、图表、演示文稿和文字处理文档。该标准由OASIS(结构化信息标准促进组织)开发,是一种**免费**且**开放**的格式。

ODF格式在免费软件和专有软件中都有使用。最初,该格式由**OpenOffice.org**办公套件实现,并且通过**Office 2007 SP2**,Microsoft也支持ODF的子集。

本文将介绍ODF格式的基础知识,特别是其在电子表格应用程序(**OpenOffice.org Calc**和**Microsoft Office Excel 2007 SP2**)中的实现。文章展示了一个将表格数据写入/读取到*.ods文件的演示应用程序。该应用程序使用Visual Studio 2010,用C#编写。创建的*.ods文件可以使用Excel 2007 SP2或更高版本以及OpenOffice.org Calc打开。

ODF格式

OpenDocument格式支持文档表示

  • 作为单个XML文档
  • 作为包内多个子文档的集合

办公应用程序使用第二种方法,我们将详细解释。

每个ODF文件是包(ZIP文件)内多个子文档的集合,每个子文档存储了完整文档的一部分。每个子文档存储文档的特定方面。例如,一个子文档包含样式信息,另一个子文档包含文档内容。

这种方法有以下好处

  • 您无需处理整个文件即可提取特定数据。
  • 图像和多媒体现在以原生格式编码,而不是文本流。
  • 由于压缩和原生多媒体存储,文件体积更小。

包内有四个包含文件数据的子文档

  • content.xml - 文档内容和内容中使用的自动样式
  • styles.xml - 文档内容使用的样式以及样式本身使用的自动样式
  • meta.xml - 文档元信息,例如作者或最后保存操作的时间
  • settings.xml - 应用程序特定设置,例如窗口大小或打印机信息

除此之外,包内**可能**还有许多其他子文档,如文档缩略图、图像等。

要读取ODF文件中的数据,您需要

  1. 将包打开为ZIP存档
  2. 找到包含您要读取的数据的部分
  3. 读取您感兴趣的部分

另一方面,如果您想创建一个新的ODF文件,您需要

  1. 创建/获取所有必要的部分
  2. 将所有内容打包成具有适当扩展名的ZIP文件

电子表格文档

电子表格文档文件是ODF文件的子集。电子表格文件具有*.ods*文件扩展名。

内容(工作表)存储在content.xml子文档中。

ReadWriteOds/image1.png

图 1:content.xml子文档。

正如我们在图 1 中看到的,工作表存储为XML元素。它们包含列和行定义,行包含单元格,依此类推……图中显示的是一个特定文档的数据,但由此我们可以看到content.xml文件的基本结构(您也可以下载完整的ODF规范)。

实现

我们的演示应用程序是使用Visual Studio 2010编写的C# WPF应用程序(图 2)。

ReadWriteOds/image2.png

图 2:演示应用程序。

该应用程序可以

  • 创建一个新的电子表格文档。
  • 读取现有的电子表格文档。
  • 写入创建的电子表格文档。

创建新文档和应用程序的底层模型

在内部,电子表格文档存储为DataSet。每个工作表由DataTable表示,工作表的行由DataRow表示,工作表的列由DataColumn表示。因此,要创建一个新文档,我们必须创建一个新的DataSet,其中包含DataTables。每个DataTable都有满足我们需求的行数和列数。

为了显示我们DataSet中的数据(并允许编辑这些数据),应用程序动态创建带有DataGridViews的选项卡(这些选项卡连接到我们的DataTables)。

通过界面,用户可以读取、写入、编辑数据并向电子表格文档添加新行。

由于应用程序基本上将电子表格文档转换为/从DataSet 转换,因此它也可以用作Excel到DataSet导出/导入场景的参考。

Zip组件和XML解析器

虽然System.IO.Packaging命名空间(.NET 3.0)中的类提供了一种读取和写入ZIP文件的方法,但它们需要不同格式的ZIP文件。因此,我们的演示使用了名为DotNetZip的开源组件。

使用ZIP组件,我们可以提取文件,获取子文档,替换(或添加)我们想要的子文档,并将该文件保存为.ods文件(这是一个ZIP文件)。

对于文档处理,我们使用了XmlDocument,因为它提供了一种轻松访问所需部分的方法。请注意,如果性能对您至关重要,您应该使用XmlTextReaderXmlTextWriter。该解决方案需要更多的工作(和代码),但提供了更好的性能。

读取电子表格文档

要读取文档,我们遵循以下步骤

  1. 提取*.ods*文件
  2. 获取content.xml文件(其中包含工作表数据)
  3. content.xml文件创建一个XmlDocument对象
  4. 创建一个DataSet(表示电子表格文件)
  5. 使用XmlDocument,我们选择"table:table"元素,然后创建相应的DataTables
  6. 我们解析"table:table"元素的子项,并将数据填充到DataTables
  7. 最后,我们返回DataSet并将其显示在应用程序的界面中

尽管ODF规范提供了一种指定默认行、列和单元格样式的方法,但实际实现存在一个糟糕的做法(尤其是在Excel中),它们宁愿将工作表写入为具有最大列数和最大行数的工作表,然后写入所有具有其样式的单元格。因此,您可能会看到您的工作表有超过1000列(Calc中有1024列,Excel中有16384列),甚至更多行(每行包含的单元格数量等于列数),尽管您只需要向前几行/列写入数据。

ODF规范提供了一种方法,您可以指定某个元素(如列/行/单元格),然后指定它重复的次数。因此,上述行为不会影响文件大小,但会使我们的实现变得复杂。

因此,我们不能仅仅读取列数并向DataTable添加等量的DataColumns(因为性能问题)。在此实现中,我们宁愿读取单元格,如果它们有数据,我们首先创建它们所属的行/列,然后将这些单元格添加到DataTable中。因此,最终我们只分配了我们需要的空间。

写入电子表格文档

要写入文档,我们遵循以下步骤

  1. 提取template.ods文件(我们用作模板的*.ods*文件)
  2. 获取content.xml文件
  3. content.xml文件创建一个XmlDocument对象
  4. content.xml文件中删除所有"table:table"元素
  5. 从我们的DataSet读取数据并组合相应的"table:table"元素
  6. 将"table:table"元素添加到content.xml文件中
  7. 将该文件压缩为新的*.ods*文件。

在此应用程序中,作为模板,我们必须使用一个空文档。但是,应用程序可以很容易地修改为使用其他模板(这样您就可以保留样式等)。

下载链接

您可以在此处下载演示应用程序的最新版本(包括C#源代码)。

历史

  • 2009年7月24日:首次发布
  • 2011年7月28日:项目从Visual Studio 2008 Windows Forms项目转换为Visual Studio 2010 WPF项目
© . All rights reserved.