All articles| All Pictures| All Softwares| All Video| Go home page| Write articles| Upload pictures

Reading number is top 10 articles
数据库2005,日志收缩简便方法_mssql学习_编程技术
SQL,SERVER,数据类型详解_mssql学习_编程技术
ASP.NET中的File类和Directory类的相关知识_[Asp.Net教程]
asp.net判断页面加载所用时间_[Asp.Net教程]
ASP.NET,2.0高级数据处理之数据绑定语法_.net资料_编程技术
当ASP.NET撞上JSF之构建应用程序的异同_[Asp.Net教程]
详细介绍:Apache+PHP+MySQL配置攻略_[PHP教程]
SQL备份语句_mssql学习_编程技术
GridView,实现服务器端和客户端全选的两种方法_[Asp.Net教程]
在ASP.NET中为GridView添加删除提示框_[Asp.Net教程]
Reading number is top 10 pictures
NeedWallpaper1
关于提肛的健身效果
Discharge accidentally Actresses by the breast1
Magnificent cloud2
Sexy women in 2013--1
So beauty, will let you spray blood2
The little woman's bright wire1
关于海盗的研究2
猫眯也疯狂
采访谢楠
Download software ranking
Wild things 2
Jinling thirteen stock
Unix video tutorial2
JSP+Ajax Web development typical examples
WebService在.NET中的实战应用教学视频 → 第5集
Be there or be square
超级战舰
Boxer Classic video1
Rio big adventure
SP3 for SQL2000
aaa published in(发表于) 2013/12/18 8:07:23 Edit(编辑)
使用,C#,编程对,RTF,文档进行操作_.net资料_编程技术

使用,C#,编程对,RTF,文档进行操作_.net资料_编程技术

使用 C# 编程对 RTF 文档进行操作_.net资料_编程技术-你的首页-uuhomepage.com

  笔者正在用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文档的内容了,其内容如下。


  {


  \rtf1\ansi\ansicpg936\deff0\deflang1033\deflangfe2052


  {\fonttbl


  {\f0\fmodern\fprq6\fcharset134 \'cb\'ce\'cc\'e5;}


  }


  {\colortbl ;\red0\green0\blue255;}


  {\*\generator Msftedit 5.41.15.1507;}


  \viewkind4\uc1\pard\cf1\lang2052\f0\fs20 Hellow\cf0\par


  }


  此处为了便于阅读,对代码进行了缩进处理,实际上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#代码如下:



  ///
  /// RTF文档书写器
  ///
  ///
  /// 本书写器对生成RTF文档提供了基础的支持
  /// 编制 袁永福 http://www.xdesigner.cn
  ///
  public class RTFWriter : System.IDisposable
  {
  #region 测试代码 ******************************************************
  [System.STAThread]
  static void Main()
  {
  TestWriteFile();
  TestClipboard();
  }
  ///
  /// 测试生成RTF文件
  /// 执行这个函数后可以使用 MS Word 打开文件 c:\a.rtf
  ///
  internal static void TestWriteFile( )
  {
  RTFWriter w = new RTFWriter( "c:\\a.rtf" ) ;
  TestBuildRTF( w );
  w.Close();
  System.Windows.Forms.MessageBox.Show("好了,你可以打开文件 c:\\a.rtf 了.");
  }
  ///
  /// 测试生成RTF文档并设置到系统剪切板中
  /// 执行这个函数后就可以在 MS Word中使用粘贴操作来显示程序生成的文档了
  ///
  internal static void TestClipboard()
  {
  System.IO.StringWriter myStr = new System.IO.StringWriter();
  RTFWriter w = new RTFWriter( myStr );
  TestBuildRTF( w );
  w.Close();
  System.Windows.Forms.DataObject data = new System.Windows.Forms.DataObject();
  data.SetData( System.Windows.Forms.DataFormats.Rtf , myStr.ToString());
  System.Windows.Forms.Clipboard.SetDataObject( data , true );
  System.Windows.Forms.MessageBox.Show("好了,你可以在MS Word 中粘贴文本了.");
  }
  ///
  /// 测试生成RTF文档
  ///
  /// RTF文档书写器
  private static void TestBuildRTF( RTFWriter w )
  {
  w.Encoding = System.Text.Encoding.GetEncoding( 936 );
  // 输出文件头
  w.WriteStartGroup();
  w.WriteKeyword("rtf1");
  w.WriteKeyword("ansi");
  w.WriteKeyword("ansicpg" + w.Encoding.CodePage );
  // 输出字体表
  w.WriteStartGroup();
  w.WriteKeyword("fonttbl");
  w.WriteStartGroup();
  w.WriteKeyword("f0");
  w.WriteText("隶书;");
  w.WriteEndGroup();
  w.WriteStartGroup();
  w.WriteKeyword("f1");
  w.WriteText("宋体;");
  w.WriteEndGroup();
  w.WriteEndGroup();
  // 输出颜色表
  w.WriteStartGroup();
  w.WriteKeyword("colortbl");
  w.WriteText(";");
  w.WriteKeyword("red0");
  w.WriteKeyword("green0");
  w.WriteKeyword("blue255");
  w.WriteText(";");
  w.WriteEndGroup();
  // 输出正文
  w.WriteKeyword("qc"); // 设置居中对齐
  w.WriteKeyword("f0"); // 设置字体
  w.WriteKeyword("fs30"); // 字体大小
  w.WriteText("这是第一段文本 ");
  w.WriteKeyword("cf1"); // 设置颜色
  w.WriteText("隶书 ");
  w.WriteKeyword("cf0"); // 设置为默认颜色
  w.WriteKeyword("f1"); // 设置字体
  w.WriteText("居中对齐 ABC12345");
  w.WriteKeyword("par"); // 开始新的段落
  w.WriteKeyword("pard"); // 清除居中对齐
  w.WriteKeyword("f1"); // 设置字体
  w.WriteKeyword("fs20"); // 字体大小
  w.WriteKeyword("cf1");
  w.WriteText("这是第二段文本 宋体 左对齐 ABC12345");
  // 结束输出
  w.WriteEndGroup();
  }
  #endregion
  ///
  /// 初始化对象
  ///
  /// 文本书写器
  public RTFWriter( System.IO.TextWriter w )
  {
  myWriter = w ;
  }
  ///
  /// 初始化对象
  ///
  /// 文件名
  public RTFWriter( string strFileName )
  {
  myWriter = new System.IO.StreamWriter(
  strFileName ,
  false ,
  System.Text.Encoding.ASCII );
  }
  private System.Text.Encoding myEncoding = System.Text.Encoding.GetEncoding( 936 ) ;
  ///
  /// 字符编码格式
  ///
  public System.Text.Encoding Encoding
  {
  get{ return myEncoding ;}
  set{ myEncoding = value;}
  }
  ///
  /// 内置的文本书写器
  ///
  private System.IO.TextWriter myWriter = null;
  private bool bolIndent = false;
  ///
  /// 是否使用缩进
  ///
  ///
  /// RTF文档内部不能随便缩进,提供此选项只是用于生成便于阅读的RTF文档,便于程序的调试,
  /// 在开发调试中可以设置该属性为true,方便开发者能直接查看生成的RTF文档,但在生成最终运行的
  /// 程序时应当设置该属性为 false .
  ///
  public bool Indent
  {
  get{ return bolIndent ;}
  set{ bolIndent = value;}
  }
  private string strIndentString = " ";
  ///
  /// 缩进字符串
  ///
  public string IndentString
  {
  get{ return strIndentString ;}
  set{ strIndentString = value;}
  }
  ///
  /// 当前缩进层次
  ///
  private int intGroupLevel = 0 ;
  ///
  /// 关闭对象
  ///
  public void Close()
  {
  if(this.intGroupLevel > 0 )
  throw new System.Exception("还有组未写完");
  if( myWriter != null )
  {
  myWriter.Close();
  myWriter = null;
  }
  }
  ///
  /// 输出一个组
  ///
  /// 关键字
  public void WriteGroup( string KeyWord )
  {
  this.WriteStartGroup();
  this.WriteKeyword( KeyWord );
  this.WriteEndGroup();
  }
  ///
  /// 开始输出组
  ///
  public void WriteStartGroup( )
  {
  if( bolIndent )
  {
  InnerWriteNewLine();
  myWriter.Write("{");
  }
  else
  myWriter.Write("{");
  intGroupLevel ++ ;
  }
  ///
  /// 结束输出组
  ///
  public void WriteEndGroup()
  {
  intGroupLevel -- ;
  if( intGroupLevel < 0 )
  throw new System.Exception("组不匹配");
  if( bolIndent )
  {
  InnerWriteNewLine();
  InnerWrite("}");
  }
  else
  InnerWrite("}");
  }
  ///
  /// 输出原始文本
  ///
  /// 文本值
  public void WriteRaw( string txt )
  {
  if( txt != null && txt.Length > 0 )
  {
  InnerWrite( txt );
  }
  }
  ///
  /// 输出关键字
  ///
  /// 关键字值
  public void WriteKeyword( string Keyword )
  {
  WriteKeyword( Keyword , false );
  }
  ///
  /// 输出关键字
  ///
  /// 关键字值
  /// 是否是扩展关键字
  public void WriteKeyword( string Keyword , bool Ext)
  {
  if( Keyword == null || Keyword.Length == 0)
  throw new System.ArgumentNullException("值不得为空");
  if( bolIndent == false && ( Keyword == "par" || Keyword == "pard" ) )
  {
  // par 或 pard 前可以输出空白行,不影响RTF文档显示
  InnerWrite( System.Environment.NewLine );
  }
  if( this.bolIndent )
  {
  if( Keyword == "par" || Keyword == "pard" )
  {
  this.InnerWriteNewLine();
  }
  }
  if( Ext )
  InnerWrite("\\*\\");
  else
  InnerWrite("\\");
  InnerWrite( Keyword );
  }
  ///
  /// 内容文本编码格式
  ///
  private System.Text.Encoding Unicode = System.Text.Encoding.Unicode ;
  ///
  /// 输出纯文本
  ///
  /// 文本值
  public void WriteText( string Text )
  {
  if( Text == null || Text.Length == 0 )
  return ;
  InnerWrite(' ');
  for( int iCount = 0 ; iCount < Text.Length ; iCount ++ )
  {
  char c = Text[ iCount ] ;
  if( c == '\t')
  {
  this.WriteKeyword("tab");
  InnerWrite(' ');
  }
  else if( c < 256 )
  {
  if( c > 32 && c < 127 )
  {
  // 出现特殊字符,需要斜线转义
  if( c == '\\' || c == '{' || c == '}' )
  InnerWrite( '\\');
  InnerWrite( c );
  }
  else
  {
  InnerWrite("\\\'");
  WriteByte( ( byte ) c );
  }
  }
  else
  {
  byte[] bs = myEncoding.GetBytes( c.ToString());
  for(int iCount2 = 0 ; iCount2 < bs.Length ; iCount2 ++ )
  {
  InnerWrite("\\\'");
  WriteByte( bs[ iCount2 ] );
  }
  }
  }//for( int iCount = 0 ; iCount < Text.Length ; iCount ++ )
  }
  ///
  /// 当前位置
  ///
  private int intPosition = 0 ;
  ///
  /// 当前行的位置
  ///
  private int intLineHead = 0 ;
  ///
  /// 16进制字符组
  ///
  private const string Hexs = "0123456789abcdef";
  ///
  /// 输出字节数组
  ///
  /// 字节数组
  public void WriteBytes( byte[] bs )
  {
  if( bs == null || bs.Length == 0 )
  return ;
  WriteRaw( " " );
  for( int iCount = 0 ; iCount < bs.Length ; iCount ++ )
  {
  if( ( iCount % 32 ) == 0 )
  {
  this.WriteRaw( System.Environment.NewLine );
  this.WriteIndent();
  }
  else if( ( iCount % 8 ) == 0 )
  {
  this.WriteRaw(" ");
  }
  byte b = bs[ iCount ] ;
  int h = ( b & 0xf0 ) >> 4 ;
  int l = b & 0xf ;
  myWriter.Write( Hexs[ h ] );
  myWriter.Write( Hexs[ l ] );
  intPosition += 2 ;
  }
  }
  ///
  /// 输出一个字节数据
  ///
  /// 字节数据
  public void WriteByte( byte b )
  {
  int h = ( b & 0xf0 ) >> 4 ;
  int l = b & 0xf ;
  myWriter.Write( Hexs[ h ] );
  myWriter.Write( Hexs[ l ] );
  intPosition += 2 ;
  //FixIndent();
  }
  #region 内部成员 ******************************************************
  private void InnerWrite( char c )
  {
  intPosition ++ ;
  myWriter.Write( c );
  }
  private void InnerWrite( string txt )
  {
  intPosition += txt.Length ;
  myWriter.Write( txt );
  }
  private void FixIndent()
  {
  if( this.bolIndent )
  {
  if( intPosition - intLineHead > 100 )
  InnerWriteNewLine();
  }
  }
  private void InnerWriteNewLine()
  {
  if( this.bolIndent )
  {
  if( intPosition > 0 )
  {
  InnerWrite( System.Environment.NewLine );
  intLineHead = intPosition ;
  WriteIndent();
  }
  }
  }
  private void WriteIndent( )
  {
  if( bolIndent )
  {
  for( int iCount = 0 ; iCount < intGroupLevel ; iCount ++ )
  {
  InnerWrite( this.strIndentString );
  }
  }
  }
  #endregion
  ///
  /// 销毁对象
  ///
  public void Dispose()
  {
  this.Close();
  }
  }



添加到del.icio.us 添加到新浪ViVi 添加到百度搜藏 添加到POCO网摘 添加到天天网摘365Key 添加到和讯网摘 添加到天极网摘 添加到黑米书签 添加到QQ书签 添加到雅虎收藏 添加到奇客发现 diigo it 添加到饭否 添加到飞豆订阅 添加到抓虾收藏 添加到鲜果订阅 digg it 貼到funP 添加到有道阅读 Live Favorites 添加到Newsvine 打印本页 用Email发送本页 在Facebook上分享


Disclaimer Privacy Policy About us Site Map

If you have any requirements, please contact webmaster。(如果有什么要求,请联系站长)
Copyright ©2011-
uuhomepage.com, Inc. All rights reserved.