返回 科技论文 首页
提高Word文档导出速度的方法研究

  摘要:BCB环境中处理应用程序导出Word文档时,大多采用OLE方式调用Word服务器或使用服务器组件控件的方法,但这两种方法都存在导出速度慢的缺陷。本文提出了使用RTF规范来实现导出Word文档的新方法,并将该方法应用于现有的RichView控件,从而改进了使用该控件导出Word文档方法的性能。文中还给出该应用的编程方法,并总结了应用程序实现Word文档导出的技术开发新路径。
  关键词:OLE 自动化服务器 RTF规范
  中图分类号:TP391.1 文献标识码:A 文章编号:1007-9416(2012)02-0152-04
  
  On Solution for Speeding-Up the Export of the Word Documents
  
  Lei Guangzhi
  Guangzhou Panocom Communication System Inc. Guangzhou, P.R.China 510300
  
  Abstract:In the BCB environment, exporting a Word document generally uses the OLE to call the Word server or server component control method, but both of them are quite slow to export the Word documents. In this paper, the new fast approach to export the Word documents is proposed and applied to the “RichView-control” and the corresponding programming method is given. The practical test results indicate that the proposed approach is fast and feasible as well as reliable compared to the corresponding current approaches.
  Key words: OLE Automation Server RTF Specification
  
  1、引言
  在BCB(Borland C++ Builder)中,实现自动导出Word文档,通常使用两种方法[1],一种是采用OLE方式调用Word服务器,而另一种则是使用服务器组件控件。这两种方法都使用了文档自动化技术,即一个应用程序(自动化客户)操纵另一应用程序对象(自动化服务器或自动化对象)的属性和方法。Microsoft Word、Excel、Outlook以自动化对象的方式展露出其内部的数据和功能,其它应用程序作为客户程序访问这些自动化对象。方法(method)和属性(property)是自动化对象的两个基本特性[2]。
  这两种方法都存在导出速度较慢的问题,在导出大批数据时要花费很长时间,使人感觉很无助。本文首先概述了这两种方法,并分析了其速度慢的原因,继而提出了根据RTF规范来实现导出大文档的新方法,该新方法可很快地处理大量数据,且调试简单方便,只要给定控制样式方法后,均能达到Word格式的给定要求。
  2、现行技术方法概述
  2.1 使用OLE方式调用服务器
  这种方式通过Varaint类,使用名字来访问word自动化对象的属性和方法。首先,通过调用静态类函数CreateObject来启动Word,调用静态函数GetActiveObject来获取对应Word的Variant对象。之后使用Variant类的OlePropertyGet、OlePropertySet、OleFunction、OleProcedure函数来操作对应word的属性、方法。
  使用名字访问Word的属性和方法,是利用IDispatch接口的Invoke成员函数调用类型信息对象的ITypeInfo::Invoke函数,进一步调用到自动化对象的所有方法和属性成员函数,这种调用方法效率比较底下[2]。事实上,我们可以通过创建一个Word文档,在其中写入特定行的文字之示例来说明这种方法处理速度缺陷,其中写入文档的代码片段如下:
  在处理器为Intel(R)Core(TM)i3-2350 CPU 2.3GGHz,内存为4.00GB,操作系统为Win7 32位的计算机上,其结果如表1所示。从中可以看出这种方法在处理3页纸(A4纸,五号字体)以上的文档时,处理速度较慢。
  2.2 使用BCB的服务器组件控件
  BCB对OFFCIE2000的所有自动化服务器进行了封装。在使用自动化服务器控件时,可以直接拖动,也可以手动添加头文件 "Word_2K_SRVR.h"至应用程序,自己定义TWordApplication、TWordDocument……等指针变量。首先初始化TWordApplication、TWordDocument指针,调用TwordApplication的Connect函数,调用TWordApplication的Documents集合的Add或Open函数创建或打开Word文档。然后,调用TWordDocument的Connect连接至TWordApplication的ActiveDocuments对象。这样,就可以使用Word_2k命名空间中ParagraphPtr、RangePtr、TablePtr等对Word段落、表格等进行控制。用上节同样Word文档的示例来检验该方法的处理速度,部分代码片段如下:
  通过前面的两张程序运行结果表的对比,使用BCB服务器组件控件要比使用OLE方式的运行速度快的多,这主要是由于在写入循环中,所有属性和方法的调用都是采用通过vtbl[3]指针调用,例如接口Range的set_text函数它的声明如下。在写入循环中,当调用虚函数时,先获取对象类的vtbl指针,再在用vtbl中自动化对象的set_text函数。
  virtual HRESULT STDMETHODCALLTYPE set_Text(BSTR prop/*[in]*/) = 0; // [0]
  使用BCB服务器组件控件虽然速度较快,但处理几十页、几百页时,仍然要数十秒,甚至更长时间,这主要是由于word程序自己的处理造成的,因为它还要关注文件内容的排版渲染、附件功能(如拼写检查、符号转换等)。
  以上两种方式都属于进程外调用自动化服务器函数的方式,还存在编码、调试困难的问题,经常要借助于VBA来获取更多的帮助。
  3、基于RTF规范提高导出Word文件速度的方案
  多文本格式 (Rich Text Format,RTF) 是一种类似Word文档的文件,并与Word文档有很好的兼容性,而Word中大多格式在RTF中也可以实现。RTF规范是对文本和图片进行格式化编码的方法,以便在应用程序之间进行传递文档[4]。采用RTF规范对文本和图片进行格式化后,可用于各种输出设备、操作环境和操作系统进行显示和打印。Microsoft Word办公软件完全支持RTF规范。


  3.1 直接基于RTF规范编程
  根据RTF规范导出Word文件,就是使用规范中的“\”、“{”、“}”、“\*”等符号将一些格式控制信息、待输出信息用文本组织起来,输出至目标文件中。一般地,所有的控制信息都用于控制读取者的动作,“{”、“}”成对使用代表一个组,“\”代表后面是控制字(可能后跟“-”+数字或数字),控制字以非字母和数字字符隔开。根据RTF规范输出指定行数的文字至Word文档的代码片段如下:
  int iFileHandle;
  AnsiString WordFileName =
   ExtractFileDir(ParamStr(0))
   +"\\test.doc";
  iFileHandle = FileCreate(WordFileName);
  AnsiString strLine;
  strLine = "{\\rtf1";
  strLine+= "{\\colortbl;";
  strLine+= "\\red0\\green0\\blue0;”;
  strLine+= "\\red0\\green0\\blue255;}";
  for(int i = 0; i < nCount ;i++)
  {
   strLine+= "\\fs24\\cf2 “;
   strLine.cat_sprintf("第\\b%06d行\\b0 ",
   i);
   strLine += "\\cf0\\par";
  }
  strLine += "\\par}";
  FileWrite(iFileHandle,
   strLine.c_str(), strLine.Length());
  FileClose(iFileHandle);
  在上面代码中,“\rtf1”指定了RTF的版本。在颜色表“\colortbl”中指定了两种颜色,第一种颜色RGB(0,0,0)是默认颜色;第二种颜色RGB(0,0,255)是自定义颜色。“\cf2”表示前景色使用第二种颜色,“\cf0”表示关闭前景色设置;“\b”表示字体加粗,“\b0”表示关闭字体加粗设置。“\fs24”表示字体大小为12磅或小四(以0.5磅为1格);“\par”表示开始一个新段落。
  用上述同例测试该程序的运行速度,其结果总结如表3所示,其中“保存关闭时间”以“---”表示意指处理时间非常小,可以忽略。
  表格的行以“\trowd”开始,以“\row”结束。“\trhdr”代表当表格分布在多页时,该行作为标题行出现在每页的行头。“\trleft0”表格最最左边相对列的位置。“\trrh262”代表行高为262twips(262×2.54/1440=0.46厘米),若为0表示自适应单元格内容,正数代表最小值,负数代表绝对值。“\pard”代表将段落格式置为默认。“\intbl”代表当前段落是表格的一部分。“\cellx2211”代表单元格右边界距离表格最左边界的宽度是2211twips(2211×2.54/1440=3.90厘米)。
  3.2 基于RTF规范对现有控件进行改进来实现导出的方法
  从上面的编码过程看出,直接使用RTF规范编程导出Word文档的代码非常简捷,但对导出样式复杂的Word文档任务,编码难度就较大。但这一困难可通过结合现有的一些控件来克服。事实上,RichView控件可直接输出Word文档,但这种控件存在一些缺陷,输出页眉、页脚不方便、不具备两端对齐功能等。鉴于可以借助于该控件完成大部分的编码,我们再植入部分RTF编码来达到输出指定样式的Word文档的预定目的。
  对于输出指定行数文字,这种方法的使用及其处理速度测试的程序代码片段现给定如下:
  myRichView->Clear();
  long time1 = GetTickCount();
  myRichView->DocParameters->Units = rvuCentimeters;
  myRichView->DocParameters->PageWidth = 21;
  myRichView->DocParameters->PageHeight = 29.7;
  myRichView->DocParameters->TopMargin = 3.17;
  myRichView ->DocParameters->BottomMargin = 3.17;
  myRichView->DocParameters->LeftMargin = 2.54;
  myRichView->DocParameters->RightMargin = 2.54;
  myRichView->RTFOptions << rvrtfSaveDocParameters;
  RVStyle1->TextStyles->Clear();
  RVStyle1->ParaStyles->Clear();
  TFontInfo* fontInfo = RVStyle1->TextStyles->Add();
  fontInfo->FontName = "黑体";
  fontInfo->Size = 10;
  fontInfo->Style = TFontStyles()<  TParaInfo* paraInfo = RVStyle1->ParaStyles->Add();
  paraInfo->Alignment = rvaLeft;
  paraInfo->LeftIndent = 0;
  paraInfo->RightIndent = 0;
  paraInfo->Options = TRVParaOptions();
  int nCount = StrToInt(LabeledEdit1->Text);
  long time2 = GetTickCount();
  for(int i = 0; i < nCount; i++)
  {
   AnsiString strLine;
   strLine.cat_sprintf("第%06d行",i);
   myRichView->AddNL(strLine, 0, 0);
  }
  myRichView->Format();
  long time3 = GetTickCount();
  AnsiString strTemp = ExtractFileDir(ParamStr(0));
  strTemp += "\\test1.doc";
  AnsiString strLine = "{\\footer\\pard\\qc\brdrt\ \brdrs\\brdrw10\\brsp100\\fs18 ";
  strLine += "Page {\\field{\\*\\fldinst PAGE}{\\fldrslt 1}} of ";
  strLine += "{\\field{\\*\\fldinst NUMPAGES}{\\fldrslt 1}} \\par}"
  myRichView->InserStrAndSaveFile(strTemp,


   strLine,
   "\\bblue\\d*;\\}\\b",
   mAfter, false);
  long time4 = GetTickCount();
  AnsiString strText = "";
  strText.cat_sprintf("输出WORD文件结束!\n总时间:%dms\n",time4-time1);
  strText.cat_sprintf("准备时间:%dms\n",time2-time1);
  strText.cat_sprintf("写入时间:%dms\n",time3-time2);
  strText.cat_sprintf("格式化保存时间:%dms\n",time4-time3);
  Application->NormalizeTopMosts();
  Application->MessageBox(strText.c_str(), "输出RTF", MB_OK);
  Application->RestoreTopMosts();
  上述代码的执行顺序为,(1)设置度量单位为厘米,设置页宽、页高为A4纸竖向大小,页边距设置为Word通用边距值;(2)清空所有预存文本格式及段落格式,分别自定义一个文本格式(序号0)及一个段落格式(序号0);(3)通过调用AddNL函数按自定义的文本格式(序号0)及段落格式(序号0)增加文本;(4)通过调用Format函数,在控件中按格式显示出所写数据;(5)通过调用InserStrAndSaveFile函数,将控件中的格式化文本保存至文件,并在文件中插入页脚(代码中的黑体加下横线部分)。
  “\footer”表示在所有页插入页脚,“\qc”表示段落居中,“\brdrt”表示段落上部有边框线,“\brdrs”表示使用单线边框,“\brdrw10”表示变现粗细(单位是twips,不能大于75),\\brsp100表示边框与段落之间距离,“\field”表示后续存在一个域,“{\*\fldinst PAGE}”表示插入PAGE域,“{\fldrslt 1}”表示域的值默认为1,“{\*\fldinst NUMPAGES}”表示插入NUMPAGES域。
  在代码中,myRichView是改进了RichView控件类的实例,InserStrAndSaveFile函数使用SaveRTF函数保存文件,并将字符串插入文件中指定字符串的位置。第1个参数为目标文件名;第二个参数为要插入的字符串;第三个参数为要查找的字符串,使用正则表达式表示(即要查找以“blue”单词开始后跟数字、分号、大括号的字符串);第4个参数为插入模式(mAfter表示在查找字符串之后插入)。根据程序的运行结果总结出下表的数据:
  表4 基于RTF规范对现有控件进行改进后测试结果
  
  对比表3可看出,相比采用RTF规范直接编码该方法虽然速度较慢,这主要是由于控件的格式显示占用时间造成的(插入页脚部分的时间基本可以忽略),但比本文介绍的前两种方法快的多。直接使用控件方法编码较为容易,对于一些控件不支持的格式,可以采用基于RTF规范直接编码来弥补。
  4、结语
  采用OLE方式调用服务器的优点是:(1)所有的高级编程语言都支持;(2)通过名字调用比较直观。缺点是:(1)依赖于已安装OFFICE组件;(2)调试困难;(3)速度慢,至适用于导出几页纸的Word文件。
  采用服务器组件控件优点是(1)速度相对于OLE方式调用服务器要快;(2)编程方便。缺点是(1)依赖于已安装OFFICE组件;(2)需要导入类型库,生成头文件;(3)调试困难;(4)速度较慢,使用几十页纸以内的Word文件导出。
  基于RTF规范导出Word文件导出的优点是:(1)导出速度快,不受Word文件大小限制;(2)调试方便;(3)很容易实现所见即所得编程;(4)可以充分利用/借助现有的一些控件。缺点是:(1)需要熟悉RTF规范;(2)当Word的格式要求比较特殊时,可能会需较多的离线(off-line)时间来制定RTF规范的样式控制。
  参考文献
  [1]牛连强,严明,田野. BCB环境下的OLE服务器组件及其调用规范研究[J].沈阳工业大学学报,28(1);86-90.
  [2]潘爱民.COM原理与应用[M].北京:清华大学出版社,1999.
  [3]Dale Rogerson,杨秀章,江英.COM技术内幕――微软组件对象模型[M].北京:清华大学出版社,1999.
  [4]Rich Text Format (RTF) Specification RTF Version 1.9.1,Microsoft Technical Support [S].2008.3.
  作者简介
  雷广智(1975――),男,1997年7月获西安交通大学电子系学士学位。此后在广州智讯通信系统有限公司依次从事工程开发、市场策划、质量控制与评定、体系管理等工作,历任工程开发经理、产品质量总监、总经理专项助理。已发表论文数篇。研究方向为通信系统中的体系结构、可靠性建模与分析、增值业务开发与扩展、高保真语音处理等。



【相关论文推荐】
  • 将Access数据库中图文信息导出到Word文档的方法
  • 教你快速提高Word文档编辑速度
  • 在word文档中长文档排版处理方法的研究
  • 基于C#的Word 文档自动导出模块的设计与实现
  • WEB页面打印及导出EXCEL文档的方法
  • 提高Word 2013保存文档的效率
  • 基于Word 2010长文档的编辑方法与技巧
  • 在Word文档中插入AutoCAD图形的方法探讨
  • 浅析word文档中长文档排版处理方法