315技术社区's Archiver

购买请咨询客服QQ:604164

wolaile 发表于 2008-5-11 10:40

使用 C# 编程对 RTF 文档进行操作

笔者正在用C#开发一个名为XWriter的文本编辑器,其中需要提供对RTF文档的支持,以前从没有搞过RTF文档,因此临时突击研究了一下,经过几天的学习研究和实践,对C#操作RTF文档有所了解,因此才可以写出此文给予说明,希望能对其他人学习RTF文档格式有所帮助。

    RTF文档格式是微软提出的一种用于描述带格式文本的文档格式,上个世纪就提出来了,一直用到现在,而且很多程序都支持这种格式,微软的Office软件家族,Windows写字板软件等等都支持,而且Windows操作系统的剪切板和OLE拖拽操作也支持RTF文档,这样就允许不同的软件通过RTF格式相互交流带格式文本。比如我用的VS.NET2003中的C#代码编辑器,在其中复制了一段代码文本,在MS Word中粘贴所得就是具有高亮度显示的文本。因此RTF格式的作用还是不小的,而且RTF格式是纯文本格式,不是二进制格式,读写都不算难。

    RTF文档格式和HTML,XML之类的标记语言有点类似,原理不复杂,但内容还是比较多的,在微软的MSND中就有文章详细的介绍了RTF格式,地址是 ms-help://MS.MSDNQTR.2003FEB.2052/dnrtfspec/html/rtfspec.htm ,你用记事本打开一个RTF文档,可以发现其中也是纯文本数据,而且一般全是ANSI字符,RTF文档一般采用ASNI字符编码格式进行存储,其中是不能直接保存汉字等编码大于127的字符,要保存得使用转义字符。RTF文档中使用一对花括号"{ }"来定义一个组,组可以套嵌定义;用"\"来开始定义一个指令和转义字符;此外还能包含纯文本数据。所有的指令和转义字符都必须包含在一个组中,一个RTF文档只有一个根组,这点有点类似XML文档只能有一个根节点的规定。

    我们使用Windows写字板新建一个RTF文档,只输入"Hellow"文本,设置文本颜色为蓝色,然后保存,然后使用记事本打开刚刚保存的RTF文件,此时就能看到一个最简单的RTF文档的内容了,其内容如下。 [color=#000000]{  \rtf1\ansi\ansicpg936\deff0\deflang1033\deflangfe2052  {\fonttbl  {\f0\fmodern\fprq6\fcharset134 \[/color][color=#000000]'[/color][color=#000000]cb\'ce\'cc\'e5;} [/color]
[color=#000000]  }  {\colortbl ;\red0\green0\blue255;}  {\[/color][color=#000000]*[/color][color=#000000]\generator Msftedit [/color][color=#000000]5.41[/color][color=#000000].[/color][color=#000000]15.1507[/color][color=#000000];}  \viewkind4\uc1\pard\cf1\lang2052\f0\fs20 Hellow\cf0\par  } [/color]

    此处为了便于阅读,对代码进行了缩进处理,实际上RTF文档中空白字符是会影响到显示结果的,一般实际生成RTF文档时不要添加额外的空白字符。

    这段RTF代码第一行和最后一行是表示根组的花括号,然后是"\"开头的指令,指令名称全部由英文字母组成,若指令后面跟着若干个数字,则这些数字就是指令的参数。比如"\rtf1",这个指令名称是"rtf",参数值是"1";而"\ansi"指令名称是"ansi",没有参数。

    指令"\rtf"是每个RTF文档必备的,而且总是第一个指令,因此可以看作RTF文档的文件头标记。若一个RTF文档第一个指令不是"rtf"指令,则可以认为这个RTF文档是不合法的。

    指令"\ansicpg"就是说明该RTF文档的内容的编码格式,参数就是编码格式编号,例如"\ansicpg936"就是指明编码格式为936号字符集,对于C#程序来说,就是库函数 System.Text.Encoding.GetEncoding( 936 ) 的返回结果,也就是GB2312编码格式。RTF文档本身肯定是使用标准的ANSI格式保存的,此处指明的字符编码格式是用于处理RTF文档中的转义字符的,比如代码中由连续的转义字符 \'cb\'ce\'cc\'e5 ,程序解析RTF文档时,应当将这一串转义字符生成一个字节数组,内容为 0xcb,0xce,0xcc,0xe5,然后使用第936号编码格式对象的GetString( byte[] )函数来还原所存储的字符串,也就是"宋体"两个字。这点比HTML的转义字符处理要麻烦一些,HTML转义字符是一个指令定义一个字符,而RTF中的是一个指令定义一个字节,而汉字是双字节的字符编码,转化前还得设法获得完整的字节序列。

    指令"\fonttbl"定义了文档中使用的所有的字体的列表,RTF文本内容引用这个字体列表来获得显示文档使用的字体,这和HTML文档中统一定义CSS样式有点类似。"fonttbl"组中由若干个子组,每个子组定义一个字体,字体定义组的第一个指令为"\f",带有一个参数指明字体的编号,比如"\f0"指明这个字体编号为0,"\f1"指明字体编号为1。字体定义组还定义了关于字体的其他信息,其中最重要的就是最后的字体名称了。此演示文档中,字体的名称就是"\'cb\'ce\'cc\'e5;",经过编码后就是"宋体;",小心后面还有个分号。注意字体编号可能是不连续的,比如可以存在这样的字体表代码"{\f0 ...}{\f1 ...}{\f99 ...}{\f212 ...}",因此解析RTF字体表时要考虑这点。

    指令"\colortbl"定义了文档颜色表,RTF文档是统一引用颜色值的,文档内容的文本颜色,背景色等颜色设置都是引用颜色表的,RTF颜色表中只定义了各个颜色的RGB值,没有明确的定义编号,引用时是按照从左到右的顺序引用颜色的,而且颜色值的编号是从“1”开始计算的。此处定义了一个颜色值"\red0\green0\blue255",也就是纯蓝色。

    指令"\*\generator"是定义了文档的创建者,此处定义指令的方式比较特殊,采用了 "\*\"前缀,个人理解是定义了一种扩展指令,其他的RTF文档处理程序遇到这样的指令可以忽略不计。

    后面的指令就是开始描述RTF文档的正文了,比如"\pard"开始清除当前段落设置,当前段落设置为默认格式;"\f0"表示设置当前字体为字体表中编号为"0"的字体;"\fs20"设置字体大小,此处的字体大小为"20",单位是半个点(MSND是这样说的:Font size in half-points (the default is 24));"\cf1"表示当前文本颜色采用第一号颜色,即纯蓝色(RTF颜色表序号从1开始计算);还有纯文本数据 "Hellow"就是RTF文档的纯文本内容了。

    对于英文内容,大部分是可以直接输出到RTF文档中,但对于某些特殊字符需要进行字符转义,比如"\","{","}"等等,前面得加上转义前缀"\",因此实际上输出的是"\\","\{","\}",这类似C语言的转义字符处理。对于制表符,得输出"\tab",对于编码大于256的字符,例如汉字,得使用文本内容编码器来编码生成二进制数据,然后使用转义前缀"\'"来转义输出一个个字节编码。比如“宋体”,它的GB2312编码生成字节序列 0xcb,0xce,0xcc,0xe5,它输出到RTF文档的结果就是“\'cb\'ce\'cc\'e5”。

    RTF文档中可以嵌入图片,可以使用代码"{\pict ... }",图片组中包含了图片的二进制数据的16进制编码字符串,MSDN中关于RTF图片格式的说明不多,我对一些图片数据的格式也不清楚,因此如何处理RTF图片也没多少可说的。

    关于各种指令的详细说明可参考MSDN中的相关文章,文章地址"ms-help://MS.MSDNQTR.2003FEB.2052/dnrtfspec/html/rtfspec_16.htm#rtfspec_21"。

    我们对RTF文档格式有所了解后,就可以开始编程来操作RTF文档了,无非就是按照RTF格式来拼凑字符串而已。比如我的文本编辑器有个功能,能将编辑的内容保存为RTF格式,这时候就需要根据我的文档内容来生成RTF文档。
    首先是做一个RTF文档书写器,虽然生成RTF文档的操作可以看作拼凑RTF字符串,但在编程实践中不能真的这么拼凑,得仿造System.Xml.XmlWriter来做一个RTF文档书写器,我编了个名为RTFWriter的RTF文档书写器,该书写器内部实现了基础的RTF文档格式的控制,能保证输出正确的RTF文档,它还提供了比较方便的编程接口,便于其他程序模块调用。这个RTF文档书写器完整的C#代码如下:
[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]class[/color][color=#000000] RTFWriter : System.IDisposable  {  [/color][color=#0000ff]#region[/color][color=#000000] 测试代码 ****************************************************** [/color][color=#000000]  [System.STAThread]  [/color][color=#0000ff]static[/color]
[color=#0000ff]void[/color][color=#000000] Main()  {  TestWriteFile();  TestClipboard();  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 测试生成RTF文件  [/color][color=#808080]///[/color][color=#008000] 执行这个函数后可以使用 MS Word 打开文件 c:\a.rtf  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]internal[/color]
[color=#0000ff]static[/color]
[color=#0000ff]void[/color][color=#000000] TestWriteFile( )  {  RTFWriter w [/color][color=#000000]=[/color]
[color=#0000ff]new[/color][color=#000000] RTFWriter( [/color][color=#000000]"[/color][color=#000000]c:\\a.rtf[/color][color=#000000]"[/color][color=#000000] ) ;  TestBuildRTF( w );  w.Close();  System.Windows.Forms.MessageBox.Show([/color][color=#000000]"[/color][color=#000000]好了,你可以打开文件 c:\\a.rtf 了.[/color][color=#000000]"[/color][color=#000000]);  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 测试生成RTF文档并设置到系统剪切板中  [/color][color=#808080]///[/color][color=#008000] 执行这个函数后就可以在 MS Word中使用粘贴操作来显示程序生成的文档了  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]internal[/color]
[color=#0000ff]static[/color]
[color=#0000ff]void[/color][color=#000000] TestClipboard()  {  System.IO.StringWriter myStr [/color][color=#000000]=[/color]
[color=#0000ff]new[/color][color=#000000] System.IO.StringWriter();  RTFWriter w [/color][color=#000000]=[/color]
[color=#0000ff]new[/color][color=#000000] RTFWriter( myStr );  TestBuildRTF( w );  w.Close();  System.Windows.Forms.DataObject data [/color][color=#000000]=[/color]
[color=#0000ff]new[/color][color=#000000] System.Windows.Forms.DataObject();  data.SetData( System.Windows.Forms.DataFormats.Rtf , myStr.ToString());  System.Windows.Forms.Clipboard.SetDataObject( data , [/color][color=#0000ff]true[/color][color=#000000] );  System.Windows.Forms.MessageBox.Show([/color][color=#000000]"[/color][color=#000000]好了,你可以在MS Word 中粘贴文本了.[/color][color=#000000]"[/color][color=#000000]);  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 测试生成RTF文档  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] RTF文档书写器 [/color]
[color=#000000]  [/color][color=#0000ff]private[/color]
[color=#0000ff]static[/color]
[color=#0000ff]void[/color][color=#000000] TestBuildRTF( RTFWriter w )  {  w.Encoding [/color][color=#000000]=[/color][color=#000000] System.Text.Encoding.GetEncoding( [/color][color=#000000]936[/color][color=#000000] );  [/color][color=#008000]//[/color][color=#008000] 输出文件头 [/color]
[color=#000000]  w.WriteStartGroup();  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]rtf1[/color][color=#000000]"[/color][color=#000000]);  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]ansi[/color][color=#000000]"[/color][color=#000000]);  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]ansicpg[/color][color=#000000]"[/color]
[color=#000000]+[/color][color=#000000] w.Encoding.CodePage );  [/color][color=#008000]//[/color][color=#008000] 输出字体表 [/color]
[color=#000000]  w.WriteStartGroup();  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]fonttbl[/color][color=#000000]"[/color][color=#000000]);  w.WriteStartGroup();  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]f0[/color][color=#000000]"[/color][color=#000000]);  w.WriteText([/color][color=#000000]"[/color][color=#000000]隶书;[/color][color=#000000]"[/color][color=#000000]);  w.WriteEndGroup();  w.WriteStartGroup();  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]f1[/color][color=#000000]"[/color][color=#000000]);  w.WriteText([/color][color=#000000]"[/color][color=#000000]宋体;[/color][color=#000000]"[/color][color=#000000]);  w.WriteEndGroup();  w.WriteEndGroup();  [/color][color=#008000]//[/color][color=#008000] 输出颜色表 [/color]
[color=#000000]  w.WriteStartGroup();  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]colortbl[/color][color=#000000]"[/color][color=#000000]);  w.WriteText([/color][color=#000000]"[/color][color=#000000];[/color][color=#000000]"[/color][color=#000000]);  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]red0[/color][color=#000000]"[/color][color=#000000]);  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]green0[/color][color=#000000]"[/color][color=#000000]);  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]blue255[/color][color=#000000]"[/color][color=#000000]);  w.WriteText([/color][color=#000000]"[/color][color=#000000];[/color][color=#000000]"[/color][color=#000000]);  w.WriteEndGroup();  [/color][color=#008000]//[/color][color=#008000] 输出正文 [/color]
[color=#000000]  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]qc[/color][color=#000000]"[/color][color=#000000]); [/color][color=#008000]//[/color][color=#008000] 设置居中对齐 [/color]
[color=#000000]  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]f0[/color][color=#000000]"[/color][color=#000000]); [/color][color=#008000]//[/color][color=#008000] 设置字体 [/color]
[color=#000000]  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]fs30[/color][color=#000000]"[/color][color=#000000]); [/color][color=#008000]//[/color][color=#008000] 字体大小 [/color]
[color=#000000]  w.WriteText([/color][color=#000000]"[/color][color=#000000]这是第一段文本 [/color][color=#000000]"[/color][color=#000000]);  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]cf1[/color][color=#000000]"[/color][color=#000000]); [/color][color=#008000]//[/color][color=#008000] 设置颜色 [/color]
[color=#000000]  w.WriteText([/color][color=#000000]"[/color][color=#000000]隶书 [/color][color=#000000]"[/color][color=#000000]);  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]cf0[/color][color=#000000]"[/color][color=#000000]); [/color][color=#008000]//[/color][color=#008000] 设置为默认颜色 [/color]
[color=#000000]  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]f1[/color][color=#000000]"[/color][color=#000000]); [/color][color=#008000]//[/color][color=#008000] 设置字体 [/color]
[color=#000000]  w.WriteText([/color][color=#000000]"[/color][color=#000000]居中对齐 ABC12345[/color][color=#000000]"[/color][color=#000000]);  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]par[/color][color=#000000]"[/color][color=#000000]); [/color][color=#008000]//[/color][color=#008000] 开始新的段落 [/color]
[color=#000000]  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]pard[/color][color=#000000]"[/color][color=#000000]); [/color][color=#008000]//[/color][color=#008000] 清除居中对齐 [/color]
[color=#000000]  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]f1[/color][color=#000000]"[/color][color=#000000]); [/color][color=#008000]//[/color][color=#008000] 设置字体 [/color]
[color=#000000]  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]fs20[/color][color=#000000]"[/color][color=#000000]); [/color][color=#008000]//[/color][color=#008000] 字体大小 [/color]
[color=#000000]  w.WriteKeyword([/color][color=#000000]"[/color][color=#000000]cf1[/color][color=#000000]"[/color][color=#000000]);  w.WriteText([/color][color=#000000]"[/color][color=#000000]这是第二段文本 宋体 左对齐 ABC12345[/color][color=#000000]"[/color][color=#000000]);  [/color][color=#008000]//[/color][color=#008000] 结束输出 [/color]
[color=#000000]  w.WriteEndGroup();  }  [/color][color=#0000ff]#endregion[/color]
[color=#000000]  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 初始化对象  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 文本书写器 [/color]
[color=#000000]  [/color][color=#0000ff]public[/color][color=#000000] RTFWriter( System.IO.TextWriter w )  {  myWriter [/color][color=#000000]=[/color][color=#000000] w ;  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 初始化对象  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 文件名 [/color]
[color=#000000]  [/color][color=#0000ff]public[/color][color=#000000] RTFWriter( [/color][color=#0000ff]string[/color][color=#000000] strFileName )  {  myWriter [/color][color=#000000]=[/color]
[color=#0000ff]new[/color][color=#000000] System.IO.StreamWriter(  strFileName ,  [/color][color=#0000ff]false[/color][color=#000000] ,  System.Text.Encoding.ASCII );  }  [/color][color=#0000ff]private[/color][color=#000000] System.Text.Encoding myEncoding [/color][color=#000000]=[/color][color=#000000] System.Text.Encoding.GetEncoding( [/color][color=#000000]936[/color][color=#000000] ) ;  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 字符编码格式  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]public[/color][color=#000000] System.Text.Encoding Encoding  {  [/color][color=#0000ff]get[/color][color=#000000]{ [/color][color=#0000ff]return[/color][color=#000000] myEncoding ;}  [/color][color=#0000ff]set[/color][color=#000000]{ myEncoding [/color][color=#000000]=[/color][color=#000000] value;}  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 内置的文本书写器  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]private[/color][color=#000000] System.IO.TextWriter myWriter [/color][color=#000000]=[/color]
[color=#0000ff]null[/color][color=#000000];  [/color][color=#0000ff]private[/color]
[color=#0000ff]bool[/color][color=#000000] bolIndent [/color][color=#000000]=[/color]
[color=#0000ff]false[/color][color=#000000];  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 是否使用缩进  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] RTF文档内部不能随便缩进,提供此选项只是用于生成便于阅读的RTF文档,便于程序的调试,  [/color][color=#808080]///[/color][color=#008000] 在开发调试中可以设置该属性为true,方便开发者能直接查看生成的RTF文档,但在生成最终运行的  [/color][color=#808080]///[/color][color=#008000] 程序时应当设置该属性为 false .  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]bool[/color][color=#000000] Indent  {  [/color][color=#0000ff]get[/color][color=#000000]{ [/color][color=#0000ff]return[/color][color=#000000] bolIndent ;}  [/color][color=#0000ff]set[/color][color=#000000]{ bolIndent [/color][color=#000000]=[/color][color=#000000] value;}  }  [/color][color=#0000ff]private[/color]
[color=#0000ff]string[/color][color=#000000] strIndentString [/color][color=#000000]=[/color]
[color=#000000]"[/color]
[color=#000000]"[/color][color=#000000];  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 缩进字符串  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]string[/color][color=#000000] IndentString  {  [/color][color=#0000ff]get[/color][color=#000000]{ [/color][color=#0000ff]return[/color][color=#000000] strIndentString ;}  [/color][color=#0000ff]set[/color][color=#000000]{ strIndentString [/color][color=#000000]=[/color][color=#000000] value;}  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 当前缩进层次  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]private[/color]
[color=#0000ff]int[/color][color=#000000] intGroupLevel [/color][color=#000000]=[/color]
[color=#000000]0[/color][color=#000000] ;  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 关闭对象  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]void[/color][color=#000000] Close()  {  [/color][color=#0000ff]if[/color][color=#000000]([/color][color=#0000ff]this[/color][color=#000000].intGroupLevel [/color][color=#000000]>[/color]
[color=#000000]0[/color][color=#000000] )  [/color][color=#0000ff]throw[/color]
[color=#0000ff]new[/color][color=#000000] System.Exception([/color][color=#000000]"[/color][color=#000000]还有组未写完[/color][color=#000000]"[/color][color=#000000]);  [/color][color=#0000ff]if[/color][color=#000000]( myWriter [/color][color=#000000]!=[/color]
[color=#0000ff]null[/color][color=#000000] )  {  myWriter.Close();  myWriter [/color][color=#000000]=[/color]
[color=#0000ff]null[/color][color=#000000];  }  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 输出一个组  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 关键字 [/color]
[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]void[/color][color=#000000] WriteGroup( [/color][color=#0000ff]string[/color][color=#000000] KeyWord )  {  [/color][color=#0000ff]this[/color][color=#000000].WriteStartGroup();  [/color][color=#0000ff]this[/color][color=#000000].WriteKeyword( KeyWord );  [/color][color=#0000ff]this[/color][color=#000000].WriteEndGroup();  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 开始输出组  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]void[/color][color=#000000] WriteStartGroup( )  {  [/color][color=#0000ff]if[/color][color=#000000]( bolIndent )  {  InnerWriteNewLine();  myWriter.Write([/color][color=#000000]"[/color][color=#000000]{[/color][color=#000000]"[/color][color=#000000]);  }  [/color][color=#0000ff]else[/color][color=#000000]  myWriter.Write([/color][color=#000000]"[/color][color=#000000]{[/color][color=#000000]"[/color][color=#000000]);  intGroupLevel [/color][color=#000000]++[/color][color=#000000] ;  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 结束输出组  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]void[/color][color=#000000] WriteEndGroup()  {  intGroupLevel [/color][color=#000000]--[/color][color=#000000] ;  [/color][color=#0000ff]if[/color][color=#000000]( intGroupLevel [/color][color=#000000]<[/color]
[color=#000000]0[/color][color=#000000] )  [/color][color=#0000ff]throw[/color]
[color=#0000ff]new[/color][color=#000000] System.Exception([/color][color=#000000]"[/color][color=#000000]组不匹配[/color][color=#000000]"[/color][color=#000000]);  [/color][color=#0000ff]if[/color][color=#000000]( bolIndent )  {  InnerWriteNewLine();  InnerWrite([/color][color=#000000]"[/color][color=#000000]}[/color][color=#000000]"[/color][color=#000000]);  }  [/color][color=#0000ff]else[/color][color=#000000]  InnerWrite([/color][color=#000000]"[/color][color=#000000]}[/color][color=#000000]"[/color][color=#000000]);  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 输出原始文本  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 文本值 [/color]
[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]void[/color][color=#000000] WriteRaw( [/color][color=#0000ff]string[/color][color=#000000] txt )  {  [/color][color=#0000ff]if[/color][color=#000000]( txt [/color][color=#000000]!=[/color]
[color=#0000ff]null[/color]
[color=#000000]&&[/color][color=#000000] txt.Length [/color][color=#000000]>[/color]
[color=#000000]0[/color][color=#000000] )  {  InnerWrite( txt );  }  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 输出关键字  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 关键字值 [/color]
[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]void[/color][color=#000000] WriteKeyword( [/color][color=#0000ff]string[/color][color=#000000] Keyword )  {  WriteKeyword( Keyword , [/color][color=#0000ff]false[/color][color=#000000] );  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 输出关键字  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 关键字值  [/color][color=#808080]///[/color][color=#008000] 是否是扩展关键字 [/color]
[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]void[/color][color=#000000] WriteKeyword( [/color][color=#0000ff]string[/color][color=#000000] Keyword , [/color][color=#0000ff]bool[/color][color=#000000] Ext)  {  [/color][color=#0000ff]if[/color][color=#000000]( Keyword [/color][color=#000000]==[/color]
[color=#0000ff]null[/color]
[color=#000000]||[/color][color=#000000] Keyword.Length [/color][color=#000000]==[/color]
[color=#000000]0[/color][color=#000000])  [/color][color=#0000ff]throw[/color]
[color=#0000ff]new[/color][color=#000000] System.ArgumentNullException([/color][color=#000000]"[/color][color=#000000]值不得为空[/color][color=#000000]"[/color][color=#000000]);  [/color][color=#0000ff]if[/color][color=#000000]( bolIndent [/color][color=#000000]==[/color]
[color=#0000ff]false[/color]
[color=#000000]&&[/color][color=#000000] ( Keyword [/color][color=#000000]==[/color]
[color=#000000]"[/color][color=#000000]par[/color][color=#000000]"[/color]
[color=#000000]||[/color][color=#000000] Keyword [/color][color=#000000]==[/color]
[color=#000000]"[/color][color=#000000]pard[/color][color=#000000]"[/color][color=#000000] ) )  {  [/color][color=#008000]//[/color][color=#008000] par 或 pard 前可以输出空白行,不影响RTF文档显示 [/color]
[color=#000000]  InnerWrite( System.Environment.NewLine );  }  [/color][color=#0000ff]if[/color][color=#000000]( [/color][color=#0000ff]this[/color][color=#000000].bolIndent )  {  [/color][color=#0000ff]if[/color][color=#000000]( Keyword [/color][color=#000000]==[/color]
[color=#000000]"[/color][color=#000000]par[/color][color=#000000]"[/color]
[color=#000000]||[/color][color=#000000] Keyword [/color][color=#000000]==[/color]
[color=#000000]"[/color][color=#000000]pard[/color][color=#000000]"[/color][color=#000000] )  {  [/color][color=#0000ff]this[/color][color=#000000].InnerWriteNewLine();  }  }  [/color][color=#0000ff]if[/color][color=#000000]( Ext )  InnerWrite([/color][color=#000000]"[/color][color=#000000]\\*\\[/color][color=#000000]"[/color][color=#000000]);  [/color][color=#0000ff]else[/color][color=#000000]  InnerWrite([/color][color=#000000]"[/color][color=#000000]\\[/color][color=#000000]"[/color][color=#000000]);  InnerWrite( Keyword );  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 内容文本编码格式  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]private[/color][color=#000000] System.Text.Encoding Unicode [/color][color=#000000]=[/color][color=#000000] System.Text.Encoding.Unicode ;  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 输出纯文本  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 文本值 [/color]
[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]void[/color][color=#000000] WriteText( [/color][color=#0000ff]string[/color][color=#000000] Text )  {  [/color][color=#0000ff]if[/color][color=#000000]( Text [/color][color=#000000]==[/color]
[color=#0000ff]null[/color]
[color=#000000]||[/color][color=#000000] Text.Length [/color][color=#000000]==[/color]
[color=#000000]0[/color][color=#000000] )  [/color][color=#0000ff]return[/color][color=#000000] ;  InnerWrite([/color][color=#000000]'[/color]
[color=#000000]'[/color][color=#000000]);  [/color][color=#0000ff]for[/color][color=#000000]( [/color][color=#0000ff]int[/color][color=#000000] iCount [/color][color=#000000]=[/color]
[color=#000000]0[/color][color=#000000] ; iCount [/color][color=#000000]<[/color][color=#000000] Text.Length ; iCount [/color][color=#000000]++[/color][color=#000000] )  {  [/color][color=#0000ff]char[/color][color=#000000] c [/color][color=#000000]=[/color][color=#000000] Text[ iCount ] ;  [/color][color=#0000ff]if[/color][color=#000000]( c [/color][color=#000000]==[/color]
[color=#000000]'[/color][color=#000000]\t[/color][color=#000000]'[/color][color=#000000])  {  [/color][color=#0000ff]this[/color][color=#000000].WriteKeyword([/color][color=#000000]"[/color][color=#000000]tab[/color][color=#000000]"[/color][color=#000000]);  InnerWrite([/color][color=#000000]'[/color]
[color=#000000]'[/color][color=#000000]);  }  [/color][color=#0000ff]else[/color]
[color=#0000ff]if[/color][color=#000000]( c [/color][color=#000000]<[/color]
[color=#000000]256[/color][color=#000000] )  {  [/color][color=#0000ff]if[/color][color=#000000]( c [/color][color=#000000]>[/color]
[color=#000000]32[/color]
[color=#000000]&&[/color][color=#000000] c [/color][color=#000000]<[/color]
[color=#000000]127[/color][color=#000000] )  {  [/color][color=#008000]//[/color][color=#008000] 出现特殊字符,需要斜线转义 [/color]
[color=#000000]  [/color][color=#0000ff]if[/color][color=#000000]( c [/color][color=#000000]==[/color]
[color=#000000]'[/color][color=#000000]\\[/color][color=#000000]'[/color]
[color=#000000]||[/color][color=#000000] c [/color][color=#000000]==[/color]
[color=#000000]'[/color][color=#000000]{[/color][color=#000000]'[/color]
[color=#000000]||[/color][color=#000000] c [/color][color=#000000]==[/color]
[color=#000000]'[/color][color=#000000]}[/color][color=#000000]'[/color][color=#000000] )  InnerWrite( [/color][color=#000000]'[/color][color=#000000]\\[/color][color=#000000]'[/color][color=#000000]);  InnerWrite( c );  }  [/color][color=#0000ff]else[/color][color=#000000]  {  InnerWrite([/color][color=#000000]"[/color][color=#000000]\\\'[/color][color=#000000]"[/color][color=#000000]);  WriteByte( ( [/color][color=#0000ff]byte[/color][color=#000000] ) c );  }  }  [/color][color=#0000ff]else[/color][color=#000000]  {  [/color][color=#0000ff]byte[/color][color=#000000][] bs [/color][color=#000000]=[/color][color=#000000] myEncoding.GetBytes( c.ToString());  [/color][color=#0000ff]for[/color][color=#000000]([/color][color=#0000ff]int[/color][color=#000000] iCount2 [/color][color=#000000]=[/color]
[color=#000000]0[/color][color=#000000] ; iCount2 [/color][color=#000000]<[/color][color=#000000] bs.Length ; iCount2 [/color][color=#000000]++[/color][color=#000000] )  {  InnerWrite([/color][color=#000000]"[/color][color=#000000]\\\'[/color][color=#000000]"[/color][color=#000000]);  WriteByte( bs[ iCount2 ] );  }  }  }[/color][color=#008000]//[/color][color=#008000]for( int iCount = 0 ; iCount < Text.Length ; iCount ++ ) [/color]
[color=#000000]  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 当前位置  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]private[/color]
[color=#0000ff]int[/color][color=#000000] intPosition [/color][color=#000000]=[/color]
[color=#000000]0[/color][color=#000000] ;  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 当前行的位置  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]private[/color]
[color=#0000ff]int[/color][color=#000000] intLineHead [/color][color=#000000]=[/color]
[color=#000000]0[/color][color=#000000] ;  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 16进制字符组  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]private[/color]
[color=#0000ff]const[/color]
[color=#0000ff]string[/color][color=#000000] Hexs [/color][color=#000000]=[/color]
[color=#000000]"[/color][color=#000000]0123456789abcdef[/color][color=#000000]"[/color][color=#000000];  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 输出字节数组  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 字节数组 [/color]
[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]void[/color][color=#000000] WriteBytes( [/color][color=#0000ff]byte[/color][color=#000000][] bs )  {  [/color][color=#0000ff]if[/color][color=#000000]( bs [/color][color=#000000]==[/color]
[color=#0000ff]null[/color]
[color=#000000]||[/color][color=#000000] bs.Length [/color][color=#000000]==[/color]
[color=#000000]0[/color][color=#000000] )  [/color][color=#0000ff]return[/color][color=#000000] ;  WriteRaw( [/color][color=#000000]"[/color]
[color=#000000]"[/color][color=#000000] );  [/color][color=#0000ff]for[/color][color=#000000]( [/color][color=#0000ff]int[/color][color=#000000] iCount [/color][color=#000000]=[/color]
[color=#000000]0[/color][color=#000000] ; iCount [/color][color=#000000]<[/color][color=#000000] bs.Length ; iCount [/color][color=#000000]++[/color][color=#000000] )  {  [/color][color=#0000ff]if[/color][color=#000000]( ( iCount [/color][color=#000000]%[/color]
[color=#000000]32[/color][color=#000000] ) [/color][color=#000000]==[/color]
[color=#000000]0[/color][color=#000000] )  {  [/color][color=#0000ff]this[/color][color=#000000].WriteRaw( System.Environment.NewLine );  [/color][color=#0000ff]this[/color][color=#000000].WriteIndent();  }  [/color][color=#0000ff]else[/color]
[color=#0000ff]if[/color][color=#000000]( ( iCount [/color][color=#000000]%[/color]
[color=#000000]8[/color][color=#000000] ) [/color][color=#000000]==[/color]
[color=#000000]0[/color][color=#000000] )  {  [/color][color=#0000ff]this[/color][color=#000000].WriteRaw([/color][color=#000000]"[/color]
[color=#000000]"[/color][color=#000000]);  }  [/color][color=#0000ff]byte[/color][color=#000000] b [/color][color=#000000]=[/color][color=#000000] bs[ iCount ] ;  [/color][color=#0000ff]int[/color][color=#000000] h [/color][color=#000000]=[/color][color=#000000] ( b [/color][color=#000000]&[/color]
[color=#000000]0xf0[/color][color=#000000] ) [/color][color=#000000]>>[/color]
[color=#000000]4[/color][color=#000000] ;  [/color][color=#0000ff]int[/color][color=#000000] l [/color][color=#000000]=[/color][color=#000000] b [/color][color=#000000]&[/color]
[color=#000000]0xf[/color][color=#000000] ;  myWriter.Write( Hexs[ h ] );  myWriter.Write( Hexs[ l ] );  intPosition [/color][color=#000000]+=[/color]
[color=#000000]2[/color][color=#000000] ;  }  }  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 输出一个字节数据  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 字节数据 [/color]
[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]void[/color][color=#000000] WriteByte( [/color][color=#0000ff]byte[/color][color=#000000] b )  {  [/color][color=#0000ff]int[/color][color=#000000] h [/color][color=#000000]=[/color][color=#000000] ( b [/color][color=#000000]&[/color]
[color=#000000]0xf0[/color][color=#000000] ) [/color][color=#000000]>>[/color]
[color=#000000]4[/color][color=#000000] ;  [/color][color=#0000ff]int[/color][color=#000000] l [/color][color=#000000]=[/color][color=#000000] b [/color][color=#000000]&[/color]
[color=#000000]0xf[/color][color=#000000] ;  myWriter.Write( Hexs[ h ] );  myWriter.Write( Hexs[ l ] );  intPosition [/color][color=#000000]+=[/color]
[color=#000000]2[/color][color=#000000] ;  [/color][color=#008000]//[/color][color=#008000]FixIndent(); [/color]
[color=#000000]  }  [/color][color=#0000ff]#region[/color][color=#000000] 内部成员 ****************************************************** [/color][color=#000000]  [/color][color=#0000ff]private[/color]
[color=#0000ff]void[/color][color=#000000] InnerWrite( [/color][color=#0000ff]char[/color][color=#000000] c )  {  intPosition [/color][color=#000000]++[/color][color=#000000] ;  myWriter.Write( c );  }  [/color][color=#0000ff]private[/color]
[color=#0000ff]void[/color][color=#000000] InnerWrite( [/color][color=#0000ff]string[/color][color=#000000] txt )  {  intPosition [/color][color=#000000]+=[/color][color=#000000] txt.Length ;  myWriter.Write( txt );  }  [/color][color=#0000ff]private[/color]
[color=#0000ff]void[/color][color=#000000] FixIndent()  {  [/color][color=#0000ff]if[/color][color=#000000]( [/color][color=#0000ff]this[/color][color=#000000].bolIndent )  {  [/color][color=#0000ff]if[/color][color=#000000]( intPosition [/color][color=#000000]-[/color][color=#000000] intLineHead [/color][color=#000000]>[/color]
[color=#000000]100[/color][color=#000000] )  InnerWriteNewLine();  }  }  [/color][color=#0000ff]private[/color]
[color=#0000ff]void[/color][color=#000000] InnerWriteNewLine()  {  [/color][color=#0000ff]if[/color][color=#000000]( [/color][color=#0000ff]this[/color][color=#000000].bolIndent )  {  [/color][color=#0000ff]if[/color][color=#000000]( intPosition [/color][color=#000000]>[/color]
[color=#000000]0[/color][color=#000000] )  {  InnerWrite( System.Environment.NewLine );  intLineHead [/color][color=#000000]=[/color][color=#000000] intPosition ;  WriteIndent();  }  }  }  [/color][color=#0000ff]private[/color]
[color=#0000ff]void[/color][color=#000000] WriteIndent( )  {  [/color][color=#0000ff]if[/color][color=#000000]( bolIndent )  {  [/color][color=#0000ff]for[/color][color=#000000]( [/color][color=#0000ff]int[/color][color=#000000] iCount [/color][color=#000000]=[/color]
[color=#000000]0[/color][color=#000000] ; iCount [/color][color=#000000]<[/color][color=#000000] intGroupLevel ; iCount [/color][color=#000000]++[/color][color=#000000] )  {  InnerWrite( [/color][color=#0000ff]this[/color][color=#000000].strIndentString );  }  }  }  [/color][color=#0000ff]#endregion[/color]
[color=#000000]  [/color][color=#808080]///[/color][color=#008000]  [/color][color=#808080]///[/color][color=#008000] 销毁对象  [/color][color=#808080]///[/color]

[color=#000000]  [/color][color=#0000ff]public[/color]
[color=#0000ff]void[/color][color=#000000] Dispose()  {  [/color][color=#0000ff]this[/color][color=#000000].Close();  }  } [/color]

    你使用VS.NET新建一个C#工程项目后,删除自动生成的Main()函数,然后复制并粘贴这段代码,这样就可以编译运行了。

    在这个RTFWriter的基础上,你可以构造自己的RTF应用了,比如将数据库的数据导出到RTF文档中,使用RTF格式向其他程序传递数据。笔者正在开发的XWriter文本编辑器也使用RTFWriter将编辑的文档保存为RTF格式,而且实际上这篇文章是完全使用XWriter编辑的,然后导出为HTML格式,没有使用MS Word,FrontPage等其他文档编辑器,本文中的代码是在VS.NET的C#代码编辑器中直接复制-粘贴而得。

    本文只是对操作RTF文档提供了一些比较简单的说明,详细内容可以参考MSDN中关于RTF的说明,网络上的资源更是多如牛毛。RTF文档格式原理简单,但内容却不少,它是一种很古老的技术,却一直到现在还在广泛的使用,而且估计还能用上很长一段时期。其实我们在学习不断出现的新技术的时候,也可以注意那些古老的但经过时间考验的技术。

页: [1]

Powered by Discuz! Archiver 6.1.0  © 2001-2007 Comsenz Inc.