打开字处理文档以便进行只读访问

本主题介绍如何使用 Open XML SDK for Office 中的类以编程方式打开字处理文档进行只读访问。


何时打开文档以进行只读访问

有时,您需要打开文档以检查或检索某些信息,并且希望以一种可确保文档保持未更改的方式执行此操作。 在此类情况下,您希望打开文档以进行只读访问。 本操作方法主题讨论了若干种以编程方式打开只读字处理文档的方法。


创建 WordprocessingDocument 对象

在 Open XML SDK 中WordprocessingDocument, 类表示Word文档包。 若要使用Word文档,请先从文档创建 类的WordprocessingDocument实例,然后使用该实例。 从文档中创建实例后,您即可获得对包含文档文本的主文档部件的访问权限。 每个 Open XML 包都会包含一些数量的部件。 至少, WordprocessingDocument 必须包含充当文档main文本容器的 main 文档部件。 包中还可以包含其他部件。 请注意,在 Word 文档中,主文档部件中的文本在此包中使用 WordprocessingML 标记表示为 XML 形式。

若要从文档创建类实例,请调用方法之 Open 一。 提供了多种 Open 方法,每个方法都有不同的签名。 下表中列出了允许您指定文档是否可编辑的方法。

Open 方法 类库参考主题 说明
Open(String, Boolean) Open(String, Boolean) 从指定文件创建 类的实例 WordprocessingDocument
Open(Stream, Boolean) Open(Stream, Boolean) 从指定的 IO 流创建 类的 WordprocessingDocument 实例。
Open(String, Boolean, OpenSettings) Open(String, Boolean, OpenSettings) 从指定文件创建 类的实例 WordprocessingDocument
Open(Stream, Boolean, OpenSettings) Open(Stream, Boolean, OpenSettings) 从指定的 I/O 流创建 类的 WordprocessingDocument 实例。

上表仅列出了接受 Open 布尔值作为第二个参数以指定文档是否可编辑的方法。 若要打开文档以进行只读访问,请为此参数指定 false。

请注意, Open 其中两种方法基于字符串作为第一个参数创建 类的实例 WordprocessingDocument 。 代码示例中的第一个示例使用此技术。 它使用上表中的第一 Open 个方法;具有需要两个参数的签名。 第一个参数采用表示要从中打开文档的完整路径文件名的字符串。 第二个参数为 truefalse;此示例使用 false 和 指示是否要打开文件进行编辑。

下面的代码示例调用 Open 方法。

// Open a WordprocessingDocument based on a filepath.
using (WordprocessingDocument wordProcessingDocument = WordprocessingDocument.Open(filepath, false))

其他两 Open 种方法基于输入/输出流创建 类的 WordprocessingDocument 实例。 例如,如果有一个使用流输入/输出的Microsoft Office SharePoint Online应用程序,并且想要使用 Open XML SDK 来处理文档,则可以使用此方法。

以下代码示例基于流打开文档。

// Get a stream of the wordprocessing document
using (FileStream fileStream = new FileStream(filepath, FileMode.Open))

// Open a WordprocessingDocument for read-only access based on a stream.
using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(fileStream, false))

假设你有一个应用程序在 .NET Framework 类库的 System.IO.Packaging 命名空间中采用 Open XML 支持,并且你希望使用 Open XML SDK 来处理只读包。 虽然 Open XML SDK 包含接受 Package 作为第一个参数的方法重载,但没有一个方法重载将布尔值作为第二个参数来指示是否应打开文档进行编辑。

建议的方法是在创建 类的 WordprocessingDocument 实例之前,以只读方式打开包,如示例代码中的第二个示例所示。 下面的代码示例执行此操作。

// Open System.IO.Packaging.Package.
using (Package wordPackage = Package.Open(filepath, FileMode.Open, FileAccess.Read))
// Open a WordprocessingDocument based on a package.
using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(wordPackage))

打开 Word 文档包后,您即可访问主文档部件。 若要访问主文档部件的正文,请分配一个对现有文档正文的引用,如以下代码示例所示。

// Assign a reference to the existing document body or create a new one if it is null.
MainDocumentPart mainDocumentPart = wordProcessingDocument.MainDocumentPart ?? wordProcessingDocument.AddMainDocumentPart();
mainDocumentPart.Document ??= new Document();

Body body = mainDocumentPart.Document.Body ?? mainDocumentPart.Document.AppendChild(new Body());

WordProcessingML 文档的结构

文档的基本文档结构WordProcessingML由 和 body 元素组成document,后跟一个或多个块级元素(例如 p表示段落)。 段落包含一个或多个 r 元素。 r代表 run,它是具有一组通用属性(如格式设置)的文本区域。 运行包含一个或多个 t 元素。 元素 t 包含文本范围。 下面的代码示例演示 WordprocessingML 包含文本“示例文本”的文档的标记。

    <w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
      <w:body>
        <w:p>
          <w:r>
            <w:t>Example text.</w:t>
          </w:r>
        </w:p>
      </w:body>
    </w:document>

使用 Open XML SDK,可以使用与元素对应的 WordprocessingML 强类型类创建文档结构和内容。 可以在 命名空间中找到 DocumentFormat.OpenXml.Wordprocessing 这些类。 下表列出了对应于 、、bodyrpt 元素的类的document类名。

WordprocessingML 元素 Open XML SDK 类 说明
<document/> Document 主文档部件的根元素。
<body/> Body 块级结构(如段落、表格、批注和 ISO/IEC 29500 规范中指定的其他项)的容器。
<p/> Paragraph 段落。
<r/> Run 一段连续文本。
<t/> Text 文本范围。

有关 WordprocessingML 文档的各个部分和元素的整体结构的详细信息,请参阅 WordprocessingML 文档的结构


生成 WordprocessingML 标记以添加文本并尝试保存

该代码示例演示您应如何添加某些文本并尝试保存更改以表明访问是只读的。 访问 main 文档部件的正文后,可以通过添加 、 RunText 类的Paragraph实例来添加文本。 这将生成必需的 WordprocessingML 标记。 以下代码示例添加段落和一段连续文本。

// Attempt to add some text.
Paragraph para = body.AppendChild(new Paragraph());
Run run = para.AppendChild(new Run());
run.AppendChild(new Text("Append text in body, but text is not saved - OpenWordprocessingDocumentReadonly"));

// Call Save to generate an exception and show that access is read-only.
// mainDocumentPart.Document.Save();

示例代码

此处OpenWordprocessingDocumentReadOnly所示的第一个示例方法 将打开Word文档进行只读访问。 可通过传递要打开的文件的完整路径来调用此方法。 例如,下面的代码示例打开第一个命令行参数中的文件路径,以便进行只读访问。

OpenWordprocessingDocumentReadonly(args[0]);

第二个示例方法 OpenWordprocessingPackageReadonly演示如何打开 Word 文档,以便从 Package进行只读访问。 可通过传递要打开的文件的完整路径来调用此方法。 例如,下面的代码示例打开第一个命令行参数中的文件路径,以便进行只读访问。

OpenWordprocessingPackageReadonly(args[0]);

第三个示例方法 OpenWordprocessingStreamReadonly演示如何打开Word文档以从流进行只读访问。 可通过传递要打开的文件的完整路径来调用此方法。 例如,下面的代码示例打开第一个命令行参数中的文件路径,以便进行只读访问。

OpenWordprocessingStreamReadonly(args[0]);

重要

[!重要信息] 由于打开文件是为进行只读访问,所以如果取消对用于保存文件的语句的注释,程序将引发 IOException

以下是使用 C# 和 VB 编写的完整示例代码。

static void OpenWordprocessingDocumentReadonly(string filepath)
{
    // Open a WordprocessingDocument based on a filepath.
    using (WordprocessingDocument wordProcessingDocument = WordprocessingDocument.Open(filepath, false))
    {
        if (wordProcessingDocument is null)
        {
            throw new ArgumentNullException(nameof(wordProcessingDocument));
        }

        // Assign a reference to the existing document body or create a new one if it is null.
        MainDocumentPart mainDocumentPart = wordProcessingDocument.MainDocumentPart ?? wordProcessingDocument.AddMainDocumentPart();
        mainDocumentPart.Document ??= new Document();

        Body body = mainDocumentPart.Document.Body ?? mainDocumentPart.Document.AppendChild(new Body());

        // Attempt to add some text.
        Paragraph para = body.AppendChild(new Paragraph());
        Run run = para.AppendChild(new Run());
        run.AppendChild(new Text("Append text in body, but text is not saved - OpenWordprocessingDocumentReadonly"));

        // Call Save to generate an exception and show that access is read-only.
        // mainDocumentPart.Document.Save();
    }
}

static void OpenWordprocessingPackageReadonly(string filepath)
{
    // Open System.IO.Packaging.Package.
    using (Package wordPackage = Package.Open(filepath, FileMode.Open, FileAccess.Read))
    // Open a WordprocessingDocument based on a package.
    using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(wordPackage))
    {
        // Assign a reference to the existing document body or create a new one if it is null.
        MainDocumentPart mainDocumentPart = wordDocument.MainDocumentPart ?? wordDocument.AddMainDocumentPart();
        mainDocumentPart.Document ??= new Document();

        Body body = mainDocumentPart.Document.Body ?? mainDocumentPart.Document.AppendChild(new Body());

        // Attempt to add some text.
        Paragraph para = body.AppendChild(new Paragraph());
        Run run = para.AppendChild(new Run());
        run.AppendChild(new Text("Append text in body, but text is not saved - OpenWordprocessingPackageReadonly"));

        // Call Save to generate an exception and show that access is read-only.
        // mainDocumentPart.Document.Save();
    }
}


static void OpenWordprocessingStreamReadonly(string filepath)
{
    // Get a stream of the wordprocessing document
    using (FileStream fileStream = new FileStream(filepath, FileMode.Open))

    // Open a WordprocessingDocument for read-only access based on a stream.
    using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(fileStream, false))
    {


        // Assign a reference to the existing document body or create a new one if it is null.
        MainDocumentPart mainDocumentPart = wordDocument.MainDocumentPart ?? wordDocument.AddMainDocumentPart();
        mainDocumentPart.Document ??= new Document();

        Body body = mainDocumentPart.Document.Body ?? mainDocumentPart.Document.AppendChild(new Body());

        // Attempt to add some text.
        Paragraph para = body.AppendChild(new Paragraph());
        Run run = para.AppendChild(new Run());
        run.AppendChild(new Text("Append text in body, but text is not saved - OpenWordprocessingStreamReadonly"));

        // Call Save to generate an exception and show that access is read-only.
        // mainDocumentPart.Document.Save();
    }
}

另请参阅