2006年06月20日

点击看大图  关于Google的员工,有趣的话题无限多。因为虽然大家都非常清楚Google办公室里允许养狗,但Google内部的其它情况却一直很神秘。上个月我写过一个新进Googler在Google里的体验,这一次轮到Philipp了,但他得到的资料更多。请注意我在本文的标题中用了双引号把“员工”给引了起来,这是因为下面将要介绍的Googler,尽管看起来很像是一个真正的Google员工,但谁也无法确认他的身份。

  这位Googler的网名为ZorbaTHut,看起来他像是与Google Calendar及Google Video项目相关的人员。不管怎样,他曝出了不少Google内幕,相当有趣。下面是其中一些比较有趣的(无顺序):

1.Google内部最常用的编程语言是C++、Java及Python;

2.即使是Google也很难根治广告欺骗点击的问题(指AdSense);

3.应聘Google的职位是一个漫长的过程,通常需要几个月才完成;

4.Google看重的是应聘者的技能,而不是学历;

5.无法很好地掌控自己的时间的程序员不适合在Google工作;

6.Google员工的Gmail容量有1TB(即1024GB);

7.如果Google员工滥用登录系统(比如让非Google人员进入Google内部网络),那么他/她可能会被炒鱿鱼;

8.Google员工能提前试用Google未发布的产品或服务,但不能向外界透露详情;

9.Google的员工如果不喜欢在被分派到的项目工作,他可以转换项目;

10.在Google里从事非技术工作的员工同样也受到尊敬和重视;

11.在Google里会议不算多,ZorbaTHut说他自己平均每个月才开一次会;

12.Google内部的等级非常简单:程序员——>技术主管——>经理——>部门主管——>大BOSS(Larry Page/Sergey Brin/Eric Schmidt);

13.Google员工大多是反对吸烟者;

14.Google内部使用的绝大多数是基于Linux系统的电脑,员工有笔记本电脑,并且可以选择使用Mac Powerbook或者是IBM的Thinkpad(现在是联想的了);

15.绝大多数Google员工只使用Linux操作系统;

16.ZorbaTHut说他的一个同事有一天深夜在Google办公室里闲逛时,发现Larry Page和Sergey Brin开着小型的四驱车在办公室里到处跑,并且是以最高时速。几天之后他又碰上这两个人,但发现四驱车的上盖被去掉了,被新绑上一部笔记本电脑及一个摄像头;(幻灭注:天哪!)

17.Google对面试者出的题目都是极端难解答的,并且从来不会告诉他们为什么他们不能获得相关职位;

  不管ZorbaTHut是否真的是Google员工,但上面这些内幕实在精彩!即使ZorbaTHut不是真正的Google员工,如果他能说出这么多看起来非常真实的事情,那也证明他对Google有着深刻的了解了。

  

今天这个新闻成为了热点,同时也让人感到非常吃惊。这也许是有史以来最成功的Spam个案,因为它成功地骗过了Google,让Google在18天内收录了它的超过55亿个网页。这是一个前所未有的例子,同时也对Google的形象造成了一定的影响。那么到底是谁这么厉害,用什么样的方法做到这一点的呢?下面我们一起来看一下实现的方法。

  根据Monetize(via digg)的报道,下面这两个网站被Google收录的网页数量达到了惊人的几十亿:

  直接点击这里看站点一的Google收录结果

  直接点击这里看站点二的Google收录结果

  要提醒一下的是,点击上面的链接时,每个人返回的结果数并不一定相同,这是因为每个人访问的Google数据中心不一定相同。但结果都是十分惊人的。为了保存记录,我截了两个图:

点击看大图
这是站点一的收录结果,接近24亿个。

点击看大图
这是站点二的收录结果,少一些,但也接近20亿个。

  根据数据中心的结果的不同,以上两个站点能查询到的Google收录数量分别最多可达55亿个和24亿个。当然,不排除这件事曝光后Google会对这个站采取行动,估计以后查询的话,结果数量会更少。

  然而更令人吃惊的是上面的两个站点的域名都只有18天历史,也就是说这两个站在3个星期内,就已经被Google收录了几十亿个网页。更不可思议的是,这两个站点的拥有者为同一个人,并且站点的每个网页上竟然都投放着Google AdSense广告!(写到这里,我再次打开这两个站点,却找不到AdSense广告了,因为站点被曝光后站长已经快速地撤走了所有广告,但之前的确是有的)可想而知这两个站点已经从Google手里赚走了多少广告费。

  那么到底这种超级Spam是怎样实现的呢?下面是大概的方法:

1.注册一个无意义的域名,域名由数字、字母及特定符号组成。注册多一些,比如100个;

2.用服务器把这些域名及相关的子域名管理起来。为域名建立尽可能多的子域名。当然,你需要一个足够强大的服务器,因为在接下来的几个星期里,它将要承受巨大的访问压力;

3.弄来尽可能多的文章数据库。不管你是采集还是用钱买的,尽量弄多一些,至于内容是什么并不重要。最好把这些数据库中的某些字符替换成相应的ASCII码,这样就不会被搜索引擎认为是重复的内容;

4.自己编写或购买一个特定的脚本。这个脚本的作用是用来返回不同关键词的相关结果,并且有效地让数据库的内容分配到不同的子域名里。这个脚本应该能应付所有的查询。并且在服务器里设置所有的子域名都自动转向域名主页,并且由这个脚本决定显示的内容。并且你还要为这些子域名创建无限多的子域名,比如abc.xyz.com,变成123.abc.xyz.com。这是为了欺骗Google,因为Google(或者MSN、Yahoo!等)都认为一个子域名是一个新站点。这一点是成功的关键,如果你自己没有这种能力,那么最好出钱叫别人做。由于某些原因,这里只写大概。

5.发动blog评论spam攻势。把你的子域名遍布尽可能多的blog或其它网站;

6.等待几个星期,你将会有惊喜。

  上面例子中的站点可谓超级垃圾站,并且Google没能成功地识别这是一种Spam行为,反而收录了它的几十亿个网页。相比国内的一些单纯通过采集数据而建立起的垃圾站而言,这两个站的站长就聪明得多了。但无论如何,这种行为都是应该要受到所有搜索引擎的惩罚才行,否则对于广大正规做站的站长而言,是极不公平的行为。同时这种行为也会极大地损害Google在用户心里的形象,破坏用户对Google的信赖感。

  我的估计是这两个站很快就会被Google处以极刑。当然,与Spam站点作斗争是所有搜索引擎共同面对的任务,这是一个漫长的过程。但作为普通用户,我们更希望的是包括Google在内的搜索引擎可以提高识别垃圾站的能力,净化搜索结果,提高准确度。

技术的复杂性与用户体验的结合,是Marissa Mayer(VP, Search Products & User Experience, Google)对Google产品设计原则的描述(via LukeW的Notes from Design 2.0):


为专家用户设计
新用户会输入“Tell me when it will snow in NY today”,得到毫无价值的结果。下回很快会输入“weather new york”,得到的结果就更有价值。瞧!一个“专家用户”。搜索中的学习曲线,陡直而快速。
别打扰专家用户。别挡他们的道。


不要让用户思考
别让用户陷于追问“Google会做什么?”
产品的界面,不应该像那些创造产品的人的界面。
集中于易用和速度。许多门户把用户停留在他们页面上的时间,作为对成功的衡量。在页面的时间更长,意味着看更多广告,对吗?然而,这根本上背离了用户的目的。用户只想得到信息,然后离开。


特别解释
在维持用户体验时,我们需要增加特性。在增加特性/功能的刚开始,用户体验会有良好的提升。但在达到高点后,伴随而来是急速降解。
我们还没有发现这样的高点,但各种公司已开始对这种现实作出反应。
(文字不多,但很值得思考。翻译比较烂,有兴趣的还是看原文吧。)

2006年06月07日

string ll="<td>([\\S\\s]*?)</td>";
Regex r = new Regex(ll); //定义组
   Match m = r.Match("<tr class=Alt><td>解读 C# 中的正则表达式</td>");

Response.Write(m.Groups[0].Value);

显示结果为" 解读 C# 中的正则表达式"

首先让我们看两个特殊的符号’^'和’$'。他们的作用是分别指出一个字符串的开始和结束。例子如下:

"^The":表示所有以"The"开始的字符串("There","The cat"等);
"of despair$":表示所以以"of despair"结尾的字符串;
"^abc$":表示开始和结尾都是"abc"的字符串——呵呵,只有"abc"自己了;
"notice":表示任何包含"notice"的字符串。

象最后那个例子,如果你不使用两个特殊字符,你就在表示要查找的串在被查找串的任意部分——你并
不把它定位在某一个顶端。

其它还有’*',’+'和’?'这三个符号,表示一个或一序列字符重复出现的次数。它们分别表示“没有或
更多”,“一次或更多”还有“没有或一次”。下面是几个例子:

"ab*":表示一个字符串有一个a后面跟着零个或若干个b。("a", "ab", "abbb",……);
"ab+":表示一个字符串有一个a后面跟着至少一个b或者更多;
"ab?":表示一个字符串有一个a后面跟着零个或者一个b;
"a?b+$":表示在字符串的末尾有零个或一个a跟着一个或几个b。

你也可以使用范围,用大括号括起,用以表示重复次数的范围。

"ab{2}":表示一个字符串有一个a跟着2个b("abb");
"ab{2,}":表示一个字符串有一个a跟着至少2个b;
"ab{3,5}":表示一个字符串有一个a跟着3到5个b。

请注意,你必须指定范围的下限(如:"{0,2}"而不是"{,2}")。还有,你可能注意到了,’*',’+'和
‘?’相当于"{0,}","{1,}"和"{0,1}"。
还有一个’|',表示“或”操作:

"hi|hello":表示一个字符串里有"hi"或者"hello";
"(b|cd)ef":表示"bef"或"cdef";
"(a|b)*c":表示一串"a""b"混合的字符串后面跟一个"c";

‘.’可以替代任何字符:

"a.[0-9]":表示一个字符串有一个"a"后面跟着一个任意字符和一个数字;
"^.{3}$":表示有任意三个字符的字符串(长度为3个字符);

方括号表示某些字符允许在一个字符串中的某一特定位置出现:

"[ab]":表示一个字符串有一个"a"或"b"(相当于"a|b");
"[a-d]":表示一个字符串包含小写的’a'到’d'中的一个(相当于"a|b|c|d"或者"[abcd]");
"^[a-zA-Z]":表示一个以字母开头的字符串;
"[0-9]%":表示一个百分号前有一位的数字;
",[a-zA-Z0-9]$":表示一个字符串以一个逗号后面跟着一个字母或数字结束。

你也可以在方括号里用’^'表示不希望出现的字符,’^'应在方括号里的第一位。(如:"%[^a-zA-Z]%"表
示两个百分号中不应该出现字母)。

为了逐字表达,你必须在"^.$()|*+?{\"这些字符前加上转移字符’\'。

请注意在方括号中,不需要转义字符。

多少年来,许多的编程语言和工具都包含对正则表达式的支持,.NET基础类库中包含有一个名字空间和一系列可以充分发挥规则表达式威力的类,而且它们也都与未来的Perl 5中的规则表达式兼容。

  此外,regexp类还能够完成一些其他的功能,例如从右至左的结合模式和表达式的编辑等。

  在这篇文章中,我将简要地介绍System.Text.RegularExpression中的类和方法、一些字符串匹配和替换的例子以及组结构的详细情况,最后,还会介绍一些你可能会用到的常见的表达式。

应该掌握的基础知识

  规则表达式的知识可能是不少编程人员“常学常忘”的知识之一。在这篇文章中,我们将假定你已经掌握了规则表达式的用法,尤其是Perl 5中表达式的用法。.NET的regexp类是Perl 5中表达式的一个超集,因此,从理论上说它将作为一个很好的起点。我们还假设你具有了C#的语法和.NET架构的基本知识。

  如果你没有规则表达式方面的知识,我建议你从Perl 5的语法着手开始学习。在规则表达式方面的权威书籍是由杰弗里·弗雷德尔编写的《掌握表达式》一书,对于希望深刻理解表达式的读者,我们强烈建议阅读这本书。

RegularExpression组合体

  regexp规则类包含在System.Text.RegularExpressions.dll文件中,在对应用软件进行编译时你必须引用这个文件,例如:

csc r:System.Text.RegularExpressions.dll foo.cs

命令将创建foo.exe文件,它就引用了System.Text.RegularExpressions文件。

名字空间简介

  在名字空间中仅仅包含着6个类和一个定义,它们是:

  Capture: 包含一次匹配的结果;
  CaptureCollection: Capture的序列;
  Group: 一次组记录的结果,由Capture继承而来;
  Match: 一次表达式的匹配结果,由Group继承而来;
  MatchCollection: Match的一个序列;
  MatchEvaluator: 执行替换操作时使用的代理;
  Regex: 编译后的表达式的实例。

  Regex类中还包含一些静态的方法:

  Escape: 对字符串中的regex中的转义符进行转义;
  IsMatch: 如果表达式在字符串中匹配,该方法返回一个布尔值;
  Match: 返回Match的实例;
  Matches: 返回一系列的Match的方法;
  Replace: 用替换字符串替换匹配的表达式;
  Split: 返回一系列由表达式决定的字符串;
  Unescape:不对字符串中的转义字符转义。

简单匹配

  我们首先从使用Regex、Match类的简单表达式开始学习。

Match m = Regex.Match("abracadabra", "(a|b|r)+");

我们现在有了一个可以用于测试的Match类的实例,例如:if (m.Success)…
如果想使用匹配的字符串,可以把它转换成一个字符串:

Console.WriteLine("Match="+m.ToString());

这个例子可以得到如下的输出: Match=abra。这就是匹配的字符串了。

字符串的替换

  简单字符串的替换非常直观。例如下面的语句:

string s = Regex.Replace("abracadabra", "abra", "zzzz");

它返回字符串zzzzcadzzzz,所有匹配的字符串都被替换成了zzzzz。

  现在我们来看一个比较复杂的字符串替换的例子:

string s = Regex.Replace(" abra ", @"^\s*(.*?)\s*$", "$1");

这个语句返回字符串abra,其前导和后缀的空格都去掉了。

  上面的模式对于删除任意字符串中的前导和后续空格都非常有用。在C#中,我们还经常使用字母字符串,在一个字母字符串中,编译程序不把字符“ \” 作为转义字符处理。在使用字符“\”指定转义字符时,@"…"是非常有用的。另外值得一提的是$1在字符串替换方面的使用,它表明替换字符串只能包含被替换的字符串。

匹配引擎的细节

  现在,我们通过一个组结构来理解一个稍微复杂的例子。看下面的例子:

string text = "abracadabra1abracadabra2abracadabra3";

  string pat = @"

    ( # 第一个组的开始

     abra # 匹配字符串abra

     ( # 第二个组的开始

     cad # 匹配字符串cad

     )? # 第二个组结束(可选)

    ) # 第一个组结束

    + # 匹配一次或多次

    ";

  //利用x修饰符忽略注释

  Regex r = new Regex(pat, "x");

  //获得组号码的清单

  int[] gnums = r.GetGroupNumbers();

  //首次匹配

  Match m = r.Match(text);

  while (m.Success)

   {

  //从组1开始

   for (int i = 1; i < gnums.Length; i++)

    {

    Group g = m.Group(gnums[i]);

  //获得这次匹配的组

    Console.WriteLine("Group"+gnums[i]+"=["+g.ToString()+"]");

  //计算这个组的起始位置和长度

    CaptureCollection cc = g.Captures;

    for (int j = 0; j < cc.Count; j++)

     {

     Capture c = cc[j];

     Console.WriteLine(" Capture" + j + "=["+c.ToString()

       + "] Index=" + c.Index + " Length=" + c.Length);

     }

    }

  //下一个匹配

   m = m.NextMatch();

   }

这个例子的输出如下所示:
     
  Group1=[abra]

      Capture0=[abracad] Index=0 Length=7

      Capture1=[abra] Index=7 Length=4

  Group2=[cad]

      Capture0=[cad] Index=4 Length=3

  Group1=[abra]

      Capture0=[abracad] Index=12 Length=7

      Capture1=[abra] Index=19 Length=4

  Group2=[cad]

      Capture0=[cad] Index=16 Length=3

  Group1=[abra]

      Capture0=[abracad] Index=24 Length=7

      Capture1=[abra] Index=31 Length=4

  Group2=[cad]

      Capture0=[cad] Index=28 Length=3

  我们首先从考查字符串pat开始,pat中包含有表达式。第一个capture是从第一个圆括号开始的,然后表达式将匹配到一个abra。第二个capture组从第二个圆括号开始,但第一个capture组还没有结束,这意味着第一个组匹配的结果是abracad ,而第二个组的匹配结果仅仅是cad。因此如果通过使用?符号而使cad成为一项可选的匹配,匹配的结果就可能是abra或abracad。然后,第一个组就会结束,通过指定+符号要求表达式进行多次匹配。

  现在我们来看看匹配过程中发生的情况。首先,通过调用Regex的constructor方法建立表达式的一个实例,并在其中指定各种选项。在这个例子中,由于在表达式中有注释,因此选用了x选项,另外还使用了一些空格。打开x选项,表达式将会忽略注释和其中没有转义的空格。

  然后,取得表达式中定义的组的编号的清单。你当然可以显性地使用这些编号,在这里使用的是编程的方法。如果使用了命名的组,作为一种建立快速索引的途径这种方法也十分有效。

  接下来是完成第一次匹配。通过一个循环测试当前的匹配是否成功,接下来是从group 1开始重复对组清单执行这一操作。在这个例子中没有使用group 0的原因是group 0是一个完全匹配的字符串,如果要通过收集全部匹配的字符串作为一个单一的字符串,就会用到group 0了。

  我们跟踪每个group中的CaptureCollection。通常情况下每次匹配、每个group中只能有一个capture,但本例中的Group1则有两个capture:Capture0和Capture1。如果你仅需要Group1的ToString,就会只得到abra,当然它也会与abracad匹配。组中ToString的值就是其CaptureCollection中最后一个Capture的值,这正是我们所需要的。如果你希望整个过程在匹配abra后结束,就应该从表达式中删除+符号,让regex引擎知道我们只需要对表达式进行匹配。

基于过程和基于表达式方法的比较

  一般情况下,使用规则表达式的用户可以分为以下二大类:第一类用户尽量不使用规则表达式,而是使用过程来执行一些需要重复的操作;第二类用户则充分利用规则表达式处理引擎的功能和威力,而尽可能少地使用过程。

  对于我们大多数用户而言,最好的方案莫过于二者兼而用之了。我希望这篇文章能够说明.NET语言中regexp类的作用以及它在性能和复杂性之间的优、劣点。

基于过程的模式

  我们在编程中经常需要用到的一个功能是对字符串中的一部分进行匹配或其他一些对字符串处理,下面是一个对字符串中的单词进行匹配的例子:

string text = "the quick red fox jumped over the lazy brown dog.";

  System.Console.WriteLine("text=[" + text + "]");

  string result = "";

  string pattern = @"\w+|\W+";

  foreach (Match m in Regex.Matches(text, pattern))

   {

  // 取得匹配的字符串

   string x = m.ToString();

  // 如果第一个字符是小写

   if (char.IsLower(x[0]))

  // 变成大写

    x = char.ToUpper(x[0]) + x.Substring(1, x.Length-1);

  // 收集所有的字符

   result += x;

   }

  System.Console.WriteLine("result=[" + result + "]");

  正象上面的例子所示,我们使用了C#语言中的foreach语句处理每个匹配的字符,并完成相应的处理,在这个例子中,新创建了一个result字符串。这个例子的输出所下所示:

  text=[the quick red fox jumped over the lazy brown dog.]

  result=[The Quick Red Fox Jumped Over The Lazy Brown Dog.]

基于表达式的模式

  完成上例中的功能的另一条途径是通过一个MatchEvaluator,新的代码如下所示:

static string CapText(Match m)

    {

  //取得匹配的字符串

    string x = m.ToString();

  // 如果第一个字符是小写

    if (char.IsLower(x[0]))

  // 转换为大写

     return char.ToUpper(x[0]) + x.Substring(1, x.Length-1);

    return x;

    }

    

   static void Main()

    {

    string text = "the quick red fox jumped over the

     lazy brown dog.";

    System.Console.WriteLine("text=[" + text + "]");

    string pattern = @"\w+";

    string result = Regex.Replace(text, pattern,

   new MatchEvaluator(Test.CapText));

    System.Console.WriteLine("result=[" + result + "]");

    }

  同时需要注意的是,由于仅仅需要对单词进行修改而无需对非单词进行修改,这个模式显得非常简单。

在我的上一篇文章《C#中使用XML——读取XML》中和大家讨论了如何使用.NET Framework中提供的类在C#中读取XML以及读取的一些相关概念,那么今天就说一说如何在C#中编写XML文档,起初我觉得用编程的方式去编写XML简直就是自讨苦吃,后来想想还是觉得挺有用的,我想Microsoft那班家伙能编出这些类来应该不是仅仅为了向比尔i盖茨交差吧!至于它的用处嘛……比如说做安装程序啊!我们可以根据在安装过程中用户所选的选项以及一些设置来生成相应的XML文档再根据XML文档来初始化我们的应用程序。空洞的话不说那么多了,下面我们来了解一下具体的实现细节。

要编写XML同样是采用流的概念,在.NET中编写XML的细节是作为XmlWriter类来实现的,但该类是抽象类不能够实例化,为此,我们要想在程序中访问它的方法以实现编写XML的愿望,必需使用它的派生类XmlTextWriter,该类提供了一系列的属性和方法为我们编写XML做准备,下面将详细的介绍这个类:

构造函数:

public XmlTextWriter(TextWriter);

public XmlTextWriter(Stream, Encoding);

public XmlTextWriter(string, Encoding);

第一个构造函数是把现有的TextWriter实例传递过去,System.IO.TextWriter类是一个有序的字符流

第二个构造函数是把要写入的流作为第一个参数,第二个参数是指定XML文档的编码方式,默认是UTF8,可取Encoding的枚举值,流可以是FileStream,MemoryStream,NetworkStream等等

第三个构造函数是把希望写入的文件名当作一个字符串(如果存在,就重写该文件)传递给第一个参数,第二个参数指定编码方式



常用的方法:

WriterStartDocument()和WriterEndDocument()方法:

第一个方法用来编写XML声明部分,如:<?xml version=”.0” encoding=”UTF-8” ?>

第二个方法用来关闭任何打开的元素或属性并将编写器重新设置为 Start 状态。



WriterStartElement()和WriteEndElement()方法:

第一个方法用来写出指定的开始标记,该方法有以下几个重载:

WriterStartElement(string localname)

使用传递的字符串作为元素的本地名称

WriterStartElement(string localname,string namespace)

第一个参数指定元素的本地名称,第二个参数指定元素所在的命名空间

WriterStartElement(string prefix,string localname,string namespace)

第一个参数指定元素的前缀,第二个参数指定元素的本地名称,第三个参数指定元素所在的命名空间

第二个方法用来写出与开始元素对应的关闭元素,如果开始元素不包含任何内容,将用一个”/>”做为关闭元素



WriterStartAttribute()和WriterEndAttribute()方法:

第一个方法用于编写一个属性的开头,该方法有两个重载:

WriterStartAttribute(string localname,string namespace)

第一个参数指定属性的本地名称,第二个参数指定属性所在的命名空间

WriterStartAttribute(string prefix,string localname,string namespace)

第一个参数指定属性的前缀,第二个参数指定属性的本地名称,第三个参数指定属性所在的命名空间

第二个方法用于关闭WriterStartAttribute创建的属性



WriterElementString()方法:

该方法可以创建一个包含字符串值的元素,它有以下重载:

WriterElementString(string localname,string value)

如果编写这样的代码:WriterElementString(“para”,”Some text”) 将输出:<para>Some text</para>

WriterElementString(string localname,string namespace,string value)

如果编写这样的代码:WriterElementString(“para”,”http://www.w.org/ns”,”Some text”) 将输出:<para xmlns=”http://www.w.org/ns”>Some text</para>

如果编写嵌套几级的元素可使用WriterStartElement()和WriterEndElement()方法,如果编写直接包含内容的元素可以使用该方法



WriterAttributeString()方法:

类似与WriterElementString()方法,在使用上如果属性的值当中不包含实体可直接使用该方法来写出属性,如果属性值包含实体可使用WriterStartAttribute()和WriterEndAttribute()方法,例如要写出这样的XML——<para author=”Do&0;a&amp;L.Perez”/>,可编写以下代码:

WriterStartElement(“para”);

WriterStartAttribute(“author”,null);

WriterString(“Do”);

WriterCharEntiry(“~n”);

WriterString(“a”);

WriterCharEntiry(“&”);

WriterString(“L.Perez”);

WriterEndAttribute();

WriterEndElement();

该方法有以下重载:

WriterAttributeString(string localname,string value);

WriterAttributeString(string localname,string namespace,string value);

WriterAttributeString(string prefx, string localname,string namespace,string value);



WriterNode(XmlReader reader,bool defattr)方法:

该方法可以从XmlReader读取器中复制节点并把它们写入XmlWriter流中,第一个参数是XmlReader的实例,第二个参数接受一个布尔值,决定是否复制元素中的属性,考虑下面XML片段:

<para>

<sent>

The<b>XmlWriter</b>class writes XML content to a Stream.

</sent>

</para>

以下代码复制其中的片段,reader代表XmlReader的实例writer代表XmlWriter类的实例:

while(reader.Read())

{

if (reader.Name == ”sent” && reader.NodeType == XmlNodeType.Element)

{

writer.WriterNode(reader,true);

}

}

得到以下输出:

<sent>

The<b>XmlWriter</b>class writes XML content to a Stream.

</sent>



WriterComment(string text)方法:用于写出注释

WriterString(string text)方法:用于写出文本

WriterCData(string text)方法:写出CDATA数据块

WriterBase6(byte[] buffer,int index,int count)方法:将指定的二进制字节编码为 Base6 并写出结果文本

Flush():将缓冲区中的所有内容刷新到基础流,并同时刷新基础流

Close():关闭此流和基础流



以上对XmlTextWriter类的一些重要方法做了简单介绍,下面我们就来看一个例程,看看在程序中如何使用这些方法,照样还是先来看下运行效果图:


Example按纽将向一个文件写出XML声明和一个元素节点以及节点内的文本,Example按纽将在Example的基础上添加属性节点,嵌套元素以及文本,WriteNode按纽使用WriterNode()方法在现有读取器中复制该读取器中的所有元素及属性并写到一个新的XML文档中,Example按纽将写一份完整的XML文档,Example按纽在Example按纽的基础上另外生成一份文档并向该文档中追加CDATA部分,Example按纽将使用WriterBase6()方法对一幅图片进行编码并将编码后的数据写到XML文档中,Example6按纽将使用Example按纽中生成的XML读取其中数据并对其中编码数据进行解码最后生成一张图片。

以下是功能实现代码:


namespace XMLWriting

{

using System;

using System.IO;

using System.Text;

using System.Xml;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;



/// <summary>

/// Form 的摘要说明。

/// </summary>

public class Form : System.Windows.Forms.Form

{

private System.Windows.Forms.TextBox textBox;

private System.Windows.Forms.Button button;

private System.Windows.Forms.Button button;

private System.Windows.Forms.Button button;

private System.Windows.Forms.Button button;

private System.Windows.Forms.Button button;

private System.Windows.Forms.Button button6;

private System.Windows.Forms.Button button7;

/// <summary>

/// 必需的设计器变量。

/// </summary>

private System.ComponentModel.Container components = null;



public Form()

{

//

// Windows 窗体设计器支持所必需的

//

InitializeComponent();



//

// TODO: 在 InitializeComponent 调用后添加任何构造函数代码

//

}



/// <summary>

/// 清理所有正在使用的资源。

/// </summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}



#region Windows 窗体设计器生成的代码

/// <summary>

/// 设计器支持所需的方法 – 不要使用代码编辑器修改

/// 此方法的内容。

/// </summary>

private void InitializeComponent()

{

this.textBox = new System.Windows.Forms.TextBox();

this.button = new System.Windows.Forms.Button();

this.button = new System.Windows.Forms.Button();

this.button = new System.Windows.Forms.Button();

this.button = new System.Windows.Forms.Button();

this.button = new System.Windows.Forms.Button();

this.button6 = new System.Windows.Forms.Button();

this.button7 = new System.Windows.Forms.Button();

this.SuspendLayout();

//

// textBox

//

this.textBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)

| System.Windows.Forms.AnchorStyles.Left)

| System.Windows.Forms.AnchorStyles.Right)));

this.textBox.Location = new System.Drawing.Point(0, 8);

this.textBox.Multiline = true;

this.textBox.Name = "textBox";

this.textBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;

this.textBox.Size = new System.Drawing.Size(78, );

this.textBox.TabIndex = 0;

this.textBox.Text = "";

//

// button

//

this.button.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));

this.button.Location = new System.Drawing.Point(0, );

this.button.Name = "button";

this.button.TabIndex = ;

this.button.Text = "Example";

this.button.Click += new System.EventHandler(this.button_Click);

//

// button

//

this.button.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));

this.button.Location = new System.Drawing.Point(88, );

this.button.Name = "button";

this.button.TabIndex = ;

this.button.Text = "Example";

this.button.Click += new System.EventHandler(this.button_Click);

//

// button

//

this.button.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));

this.button.Location = new System.Drawing.Point(76, );

this.button.Name = "button";

this.button.TabIndex = ;

this.button.Text = "WriteNode";

this.button.Click += new System.EventHandler(this.button_Click);

//

// button

//

this.button.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));

this.button.Location = new System.Drawing.Point(6, );

this.button.Name = "button";

this.button.TabIndex = ;

this.button.Text = "Example";

this.button.Click += new System.EventHandler(this.button_Click);

//

// button

//

this.button.Location = new System.Drawing.Point(, );

this.button.Name = "button";

this.button.TabIndex = ;

this.button.Text = "Example";

this.button.Click += new System.EventHandler(this.button_Click);

//

// button6

//

this.button6.Location = new System.Drawing.Point(0, );

this.button6.Name = "button6";

this.button6.TabIndex = 6;

this.button6.Text = "Example";

this.button6.Click += new System.EventHandler(this.button6_Click);

//

// button7

//

this.button7.Location = new System.Drawing.Point(8, );

this.button7.Name = "button7";

this.button7.TabIndex = 7;

this.button7.Text = "Example6";

this.button7.Click += new System.EventHandler(this.button7_Click);

//

// Form

//

this.AutoScaleBaseSize = new System.Drawing.Size(6, );

this.ClientSize = new System.Drawing.Size(78, 7);

this.Controls.Add(this.button7);

this.Controls.Add(this.button6);

this.Controls.Add(this.button);

this.Controls.Add(this.button);

this.Controls.Add(this.button);

this.Controls.Add(this.button);

this.Controls.Add(this.button);

this.Controls.Add(this.textBox);

this.Name = "Form";

this.Text = "XMLWriting";

this.ResumeLayout(false);



}

#endregion



/// <summary>

/// 应用程序的主入口点。

/// </summary>

[STAThread]

static void Main()

{

Application.Run(new Form());

}



private void button_Click(object sender, System.EventArgs e)

{

this.textBox.Text = string.Empty;

const string fileName = "WriteXml.xml";



XmlTextWriter xmlTxtWt = new XmlTextWriter(fileName,Encoding.UTF8);



// 写XML文档声明

xmlTxtWt.WriteStartDocument();

// 写XML起始元素

xmlTxtWt.WriteStartElement("ct","ContactDetails","http://www.deltabis.com/Contact");

// 写文本

xmlTxtWt.WriteString("This is a XML file");

// 写XML结束元素

xmlTxtWt.WriteEndElement();

// 写关闭文档元素

xmlTxtWt.WriteEndDocument();



xmlTxtWt.Flush(); //刷新

xmlTxtWt.Close();



this.textBox.Text = ReadXml(fileName);

}



/// <summary>

/// 读取经过编写的XML文件的所有内容

/// </summary>

/// <param name="xmlPath">文件路径</param>

/// <returns>表示内容的字符串</returns>

private string ReadXml(string xmlPath)

{

string xmlStr = string.Empty;

XmlTextReader xmlTxtRd = new XmlTextReader(xmlPath);



xmlTxtRd.MoveToContent();

xmlStr = xmlTxtRd.ReadOuterXml();



xmlTxtRd.Close();

return xmlStr;

}



private void button_Click(object sender, System.EventArgs e)

{

this.textBox.Text = string.Empty;

const string fileName = "WriteXml.xml";



XmlTextWriter xmlTxtWt = new XmlTextWriter(fileName,Encoding.UTF8);



// 设置XML的输出格式,这里使用缩进

xmlTxtWt.Formatting = Formatting.Indented;

// 设置缩进的数量,这里是个空格,IndentChar属性默认是空格

xmlTxtWt.Indentation = ;



xmlTxtWt.WriteStartDocument();

xmlTxtWt.WriteStartElement("ct","ContactDetails","http://www.deltabis.com/Contact");

xmlTxtWt.WriteAttributeString("Date","000 :00");

xmlTxtWt.WriteElementString("contact","abcd");

xmlTxtWt.WriteElementString("contact","efgh");

xmlTxtWt.WriteElementString("contact","ijkl");

xmlTxtWt.WriteElementString("contact","mnop");

xmlTxtWt.WriteEndElement();

xmlTxtWt.WriteEndDocument();



xmlTxtWt.Flush();

xmlTxtWt.Close();



this.textBox.Text = ReadXml(fileName);

}



// 从读取器中复制节点及其内容

private void button_Click(object sender, System.EventArgs e)

{

XmlTextReader xmlTxtRd = new XmlTextReader("唐诗.xml");

XmlTextWriter xmlTxtWt = new XmlTextWriter("WriteXml.xml",Encoding.UTF8);



xmlTxtWt.Formatting = Formatting.Indented;

xmlTxtWt.Indentation = ;

xmlTxtWt.WriteStartDocument();

xmlTxtWt.WriteComment("以下是从读取器中拷贝的节点");



try

{

while(xmlTxtRd.Read())

{

if (xmlTxtRd.NodeType == XmlNodeType.Element)

xmlTxtWt.WriteNode(xmlTxtRd,true);

}

}

catch(Exception exp)

{

MessageBox.Show(exp.ToString());

}

finally

{

xmlTxtWt.Flush();

xmlTxtWt.Close();

xmlTxtRd.Close();

}



this.textBox.Text = ReadXml("WriteXml.xml");

}



// 编写一份完整的XML

private void button_Click(object sender, System.EventArgs e)

{

this.textBox.Text = string.Empty;

string fileName = "WriteXml.xml";



XmlTextWriter xmlTxtWt = new XmlTextWriter(fileName,Encoding.UTF8);



xmlTxtWt.Formatting = Formatting.Indented;

xmlTxtWt.Indentation = ;



xmlTxtWt.WriteStartDocument();

xmlTxtWt.WriteStartElement("ct","ContactDetails","http://www.deltabis.com/Contact");

xmlTxtWt.WriteAttributeString("Date","000 6:00");

xmlTxtWt.WriteComment("This document contains contact information.");

xmlTxtWt.WriteStartElement("contact");

xmlTxtWt.WriteAttributeString("title",string.Empty);

xmlTxtWt.WriteStartElement("name");

xmlTxtWt.WriteElementString("firstname","Steven");

xmlTxtWt.WriteElementString("middle",string.Empty);

xmlTxtWt.WriteElementString("lastname","LivingStone-Perez");

xmlTxtWt.WriteFullEndElement();

xmlTxtWt.WriteFullEndElement();

xmlTxtWt.WriteFullEndElement();

xmlTxtWt.WriteEndDocument();



xmlTxtWt.Flush();

xmlTxtWt.Close();



this.textBox.Text = ReadXml(fileName);

}



// 添加CDATA数据块

private void button_Click(object sender, System.EventArgs e)

{

this.textBox.Text = string.Empty;

string fileName = "WriteXml.xml";



XmlTextWriter xmlTxtWt = new XmlTextWriter(fileName,Encoding.UTF8);



xmlTxtWt.Formatting = Formatting.Indented;

xmlTxtWt.Indentation = ;



xmlTxtWt.WriteStartDocument();

xmlTxtWt.WriteStartElement("ct","ContactDetails","http://www.deltabis.com/Contact");

xmlTxtWt.WriteAttributeString("Date","000 6:00");

xmlTxtWt.WriteComment("This document contains contact information.");

xmlTxtWt.WriteStartElement("contact");

xmlTxtWt.WriteAttributeString("title",string.Empty);

xmlTxtWt.WriteStartElement("name");

xmlTxtWt.WriteElementString("firstname","Steven");

xmlTxtWt.WriteElementString("middle",string.Empty);

xmlTxtWt.WriteElementString("lastname","LivingStone-Perez");

xmlTxtWt.WriteFullEndElement();

xmlTxtWt.WriteStartElement("notes","http://www.deltabis.com/Contact"); // 该节点的命名空间与上面一样,该节点将使用上面的前缀

xmlTxtWt.WriteCData("<securityAlogrithm>88hshshhhdd8*^&@^*^#*&!%~~~(ghj*(**&%^){}^(*&7*(9$%###$@!");

xmlTxtWt.WriteEndElement();

xmlTxtWt.WriteFullEndElement();

xmlTxtWt.WriteFullEndElement();

xmlTxtWt.WriteEndDocument();



xmlTxtWt.Flush();

xmlTxtWt.Close();



this.textBox.Text = ReadXml(fileName);

}



// 对图片进行编码,并写出

private void button6_Click(object sender, System.EventArgs e)

{

int readByte = 0;

int bytesToRead = 00;

string fileName = "WriteXml.xml";

this.textBox.Text = string.Empty;



// 打开图片文件,利用该图片构造一个文件流

FileStream fs = new FileStream(@"D:\0.jpg",FileMode.Open);

// 使用文件流构造一个二进制读取器将基元数据读作二进制值

BinaryReader br = new BinaryReader(fs);



XmlTextWriter xmlTxtWt = new XmlTextWriter(fileName,Encoding.UTF8);

xmlTxtWt.Formatting = Formatting.Indented;

xmlTxtWt.Indentation = ;



xmlTxtWt.WriteStartDocument();

xmlTxtWt.WriteStartElement("ct","ContactDetails","http://www.deltabis.com/Contact");

xmlTxtWt.WriteStartElement("image");

xmlTxtWt.WriteAttributeString("imageName","0.jpg");



byte[] base6buffer = new byte[bytesToRead];

do

{

readByte = br.Read(base6buffer,0,bytesToRead); //将数据读入字节数组

xmlTxtWt.WriteBase6(base6buffer,0,readByte); //将数组中二进制值编码为Base6并写出到XML文件

}while(bytesToRead <= readByte);



xmlTxtWt.WriteEndElement();

xmlTxtWt.WriteEndElement();

xmlTxtWt.WriteEndDocument();



xmlTxtWt.Flush();

xmlTxtWt.Close();



this.textBox.Text = ReadXml(fileName);

}



// 解码并生成图片

private void button7_Click(object sender, System.EventArgs e)

{

int readByte = 0;

int bytesToRead = 00;



XmlTextReader xmlTxtRd = new XmlTextReader("WriteXml.xml");



FileStream fs = new FileStream("newimage.jpg",FileMode.Create);

BinaryWriter bw = new BinaryWriter(fs);



byte[] base6buffer = new byte[bytesToRead];



while(xmlTxtRd.Read())

{

if (xmlTxtRd.NodeType == XmlNodeType.Element && xmlTxtRd.Name == "image")

{

do

{

readByte = xmlTxtRd.ReadBase6(base6buffer,0,bytesToRead);

bw.Write(base6buffer,0,readByte);

}while(readByte <= bytesToRead);

}

}



bw.Flush();

bw.Close();

fs.Close();



xmlTxtRd.Close();

}

}

}

以下是在WriteNode按纽中要使用到的XML文件:

唐诗.xml

<?xml version=".0" encoding="gb"?>

<唐诗>

<五言绝句>

<作者 字号="太白">李白</作者>

<标题>静夜思</标题>

<内容>床前明月光,疑是地上霜。举头望明月,低头思故乡。</内容>

</五言绝句>

<五言绝句>

<作者 字号="太白">李太白</作者>

<标题>春晓</标题>

<内容>春眠不觉晓,处处闻啼鸟。夜来风雨声,花落知多少。</内容>

</五言绝句>

<五言绝句>

<作者 字号="季凌">王之涣</作者>

<标题>登鹤雀楼</标题>

<内容>白日依山尽,黄河入海流。欲穷千里目,更上一层楼</内容>

</五言绝句>

<五言绝句>

<作者>李清照</作者>

<标题>如梦令</标题>

<内容>昨夜风疏雨骤,浓睡不消残酒,试问卷帘人,却道海棠依旧,知否,知否,应是绿肥红瘦。</内容>

</五言绝句>

</唐诗>

System.IO命名空间中的类为托管应用程序提供文件以及其他形式的输入输出。托管i/o的基本构件是流,而流是字节导向的数据的抽象表示。流通过System.IO.Stream类表示.

System.IO.FileStream允许将文件作为流访问;

System.IO.MemoryStream允许将内存块作为流进行访问;…………

托管和非托管的应用程序最常使用的IO形式是文件IO。托管应用程序读写文件的一般步骤如下

、用FileStream对象打开文件

、进行二进制读写操作,在FileStream对象周围包装BinaryReader和BinaryWriter的实例,并调用BinaryReader和BinaryWriter方法执行输入输出。

、要读写文本,在FileStream对象的周围包装一个StreamReader和StreamWriter,然后使用StreamReader和StreamWriter方法完成输入输出。

、关闭FileStream对象。

下面是一个简单的文本文件读操作

using System;
using System.IO;

class FileTest
{
static void Main(string [] args)
{
string filename="testfile.txt";
//打开文件并显示其内容
StreamReader reader=null;
try
{
reader=new StreamReader(filename);
for(string line=reader.ReadLine();line!=null;line=reader.ReadLine())
Console.WriteLine(line);
}
catch(IOException e)
{
Console.WriteLine(e.Message);
}
finally
{
if(reader!=null)
reader.Close();
}
}
}
/**
* FCL是一个非常丰富的类库,所以还有许多打开文件并进行读取的方法,比如
* .用File.open创建一个FileStream,并围绕它包装一个StreamReader
* FileStream stream=File.Open(filename,FileMode.Open,FileAccess.Read);
* StreamReader reader=new StreamReaderaa(stream);
* .使用File.OpenText,在一步内创建一个FileStream和一个StreamReader
* StreamReader reader=File.OpenText(filename);
* 当然,还有其他的方法
* 若要对文本进行写入操作,可以使用StreamWriter
*/

其中的异常处理是为了防止意外的事情发生,如传递给StreamReader的构造函数的文件名非法,或者在执行raeder.Close();前匡架引发异常等。

using System;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace Curllion
{
public class Crypt
{
private byte[] key;
private byte[] iv;
private System.Text.ASCIIEncoding asciiEncoding;
private System.Text.UnicodeEncoding textConverter;
private RCCryptoServiceProvider rcCSP;
public Crypt()
{
InitializeComponent();
}
private void InitializeComponent()
{
key = new byte[]{06,,,,7,,,,,9,87,,,,7,0};
iv = new byte[]{,86,,6,8,9,,};
asciiEncoding = new System.Text.ASCIIEncoding();
textConverter = new System.Text.UnicodeEncoding();
rcCSP = new RCCryptoServiceProvider();
}
/// <summary>
/// 新建一个大小为06B的文件,以便将加密数据写入固定大小的文件。
/// </summary>
/// <param name="filePath">文件保存的地址,包含文件名</param>
public void InitBinFile(string filePath)
{
byte[] tmp = new byte[06];
try //创建文件流,将其内容全部写入0
{
System.IO.FileStream writeFileStream = new FileStream(filePath,
System.IO.FileMode.Create,
System.IO.FileAccess.Write,
System.IO.FileShare.None,,false);

for(int i = 0 ;i< 06;i++)
tmp[i] = 0;
writeFileStream.Write(tmp,0,06);
writeFileStream.Flush();
writeFileStream.Close();
}
catch(System.IO.IOException)
{
MessageBox.Show("文件操作错误!","错误!",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}
/// <summary>
/// 将文本数据加密后写入一个文件,其中,这个文件是用InitBinFile建立的,这个文件将被分成十块,
/// 用来分别保存0组不同的数据,第一个byte位保留,第位到第位分别用来存放每块数据的长度,但
/// 一个byte的取值为0-7,所以,用两个byte来存放一个长度。
/// </summary>
/// <param name="toEncryptText">要加密的文本数据</param>
/// <param name="filePath">要写入的文件</param>
/// <param name="dataIndex">写入第几块,取值为–0</param>
/// <returns>是否操作成功</returns>
public bool EncryptToFile(string toEncryptText,string filePath,int dataIndex)
{
bool r = false;
if(dataIndex > 0 && dataIndex < )
{
MessageBox.Show("数据索引的取值范围在至0之间!","错误!",
MessageBoxButtons.OK,MessageBoxIcon.Error);
return r;
}
byte[] encrypted;
//打开要写入的文件,主要是为了保持原文件的内容不丢失
System.IO.FileStream tmpFileStream= new FileStream(filePath,
System.IO.FileMode.Open,
System.IO.FileAccess.Read,
System.IO.FileShare.None,0,true);

byte[] index = new byte[06];
//将读取的内容写到byte数组
tmpFileStream.Read(index,0,06);
tmpFileStream.Close();
//定义基本的加密转换运算
System.Security.Cryptography.ICryptoTransform Encryptor = rcCSP.CreateEncryptor(this.key,this.iv);
System.IO.MemoryStream msEncrypt = new MemoryStream();
//在此加密转换流中,加密将从csEncrypt,加密后,结果在msEncrypt流中。
System.Security.Cryptography.CryptoStream csEncrypt = new CryptoStream(msEncrypt,
Encryptor,CryptoStreamMode.Write);
//将要加密的文本转换成UTF-6 编码,保存在tmp数组。
byte[] tmp = textConverter.GetBytes(toEncryptText);
//将tmp输入csEncrypt,将通过Encryptor来加密。
csEncrypt.Write(tmp,0,tmp.Length);
//输出到msEnctypt
csEncrypt.FlushFinalBlock();
//将流转成byte[]
encrypted = msEncrypt.ToArray();
if(encrypted.Length>0)
{
MessageBox.Show("加密后,数据长度大于KB,无法保存");
return false;
}
//得到加密后数据的大小,将结果存在指定的位置。
index[dataIndex* - ] = Convert.ToByte(Convert.ToString(encrypted.Length/8));
index[dataIndex*] = Convert.ToByte(Convert.ToString(encrypted.Length%8));
//将加密后的结果写入index(覆盖)
for(int i=0;i<encrypted.Length;i++)
index[0*(dataIndex-)++i]=encrypted[i];
//建立文件流
tmpFileStream = new FileStream(filePath,
System.IO.FileMode.Truncate,
System.IO.FileAccess.Write,
System.IO.FileShare.None,0,true);
//写文件
tmpFileStream.Write(index,0,06);
tmpFileStream.Flush();
r = true;
tmpFileStream.Close();
return r;
}
/// <summary>
/// 从一个文件中解密出一段文本,其中,这个文件是由InitBinFile建立的,并且由 EncryptToFile加密的
/// </summary>
/// <param name="filePath">要解密的文件</param>
/// <param name="dataIndex">要从哪一个块中解密</param>
/// <returns>解密后的文本</returns>
public string DecryptFromFile(string filePath,int dataIndex)
{
string r = "";
if(dataIndex > 0 && dataIndex < )
{
MessageBox.Show("数据索引的取值范围在至0之间!","错误!",
MessageBoxButtons.OK,MessageBoxIcon.Error);
return r;
}
byte[] decrypted;
System.IO.FileStream tmpFileStream = new FileStream(filePath,
System.IO.FileMode.Open,
System.IO.FileAccess.Read,
System.IO.FileShare.None,0,true);

System.Security.Cryptography.ICryptoTransform Decryptor = rcCSP.CreateDecryptor(this.key,this.iv);
System.IO.MemoryStream msDecrypt = new MemoryStream();
System.Security.Cryptography.CryptoStream csDecrypt = new CryptoStream(msDecrypt,
Decryptor,CryptoStreamMode.Write);
byte[] index = new byte[06];

tmpFileStream.Read(index,0,06);
int startIndex = 0*(dataIndex-)+;
int count = index[dataIndex* - ]*8 + index[dataIndex*];
byte[] tmp = new byte[count];

Array.Copy(index,0*(dataIndex-)+,tmp,0,count);
csDecrypt.Write(tmp,0,count);
csDecrypt.FlushFinalBlock();
decrypted = msDecrypt.ToArray();
r = textConverter.GetString(decrypted,0,decrypted.Length);
tmpFileStream.Close();
return r;
}
/// <summary>
/// 将一段文本加密后保存到一个文件
/// </summary>
/// <param name="toEncryptText">要加密的文本数据</param>
/// <param name="filePath">要保存的文件</param>
/// <returns>是否加密成功</returns>
public bool EncryptToFile(string toEncryptText,string filePath)
{
bool r = false;
byte[] encrypted;
System.IO.FileStream tmpFileStream = new FileStream(filePath,
System.IO.FileMode.OpenOrCreate,
System.IO.FileAccess.Write,
System.IO.FileShare.None,0,true);

System.Security.Cryptography.ICryptoTransform Encryptor = rcCSP.CreateEncryptor(this.key,this.iv);
System.IO.MemoryStream msEncrypt = new MemoryStream();
System.Security.Cryptography.CryptoStream csEncrypt = new CryptoStream(msEncrypt,
Encryptor,CryptoStreamMode.Write);

byte[] tmp = textConverter.GetBytes(toEncryptText);
csEncrypt.Write(tmp,0,tmp.Length);
csEncrypt.FlushFinalBlock();
encrypted = msEncrypt.ToArray();
tmpFileStream.Write(encrypted,0,encrypted.Length);
tmpFileStream.Flush();
r = true;
tmpFileStream.Close();
return r;
}
/// <summary>
/// 将一个被加密的文件解密
/// </summary>
/// <param name="filePath">要解密的文件</param>
/// <returns>解密后的文本</returns>
public string DecryptFromFile(string filePath)
{
string r = "";
byte[] decrypted;
System.IO.FileStream tmpFileStream = new FileStream(filePath,
System.IO.FileMode.Open,
System.IO.FileAccess.Read,
System.IO.FileShare.None,0,true);
System.Security.Cryptography.ICryptoTransform Decryptor = rcCSP.CreateDecryptor(this.key,this.iv);
System.IO.MemoryStream msDecrypt = new MemoryStream();
System.Security.Cryptography.CryptoStream csDecrypt = new CryptoStream(msDecrypt,
Decryptor,CryptoStreamMode.Write);

byte[] tmp = new byte[tmpFileStream.Length];
tmpFileStream.Read(tmp,0,tmp.Length);
csDecrypt.Write(tmp,0,tmp.Length);
csDecrypt.FlushFinalBlock();
decrypted = msDecrypt.ToArray();
r = textConverter.GetString(decrypted,0,decrypted.Length);
tmpFileStream.Close();
return r;
}
//————————————————————-
/// <summary>
/// 将文本数据加密后写入一个文件,其中,这个文件是用InitBinFile建立的,这个文件将被分成十块,
/// 用来分别保存0组不同的数据,第一个byte位保留,第位到第位分别用来存放每块数据的长度,但
/// 一个byte的取值为0-7,所以,用两个byte来存放一个长度。
/// </summary>
/// <param name="toEncryptText">要加密的文本数据</param>
/// <param name="filePath">要写入的文件</param>
/// <param name="dataIndex">写入第几块,取值为–0</param>
/// <param name="IV">初始化向量</param>
/// <param name="Key">加密密匙</param>
/// <returns>是否操作成功</returns>
public bool EncryptToFile(string toEncryptText,string filePath,int dataIndex,byte[] IV,byte[] Key)
{
bool r = false;
if(dataIndex > 0 && dataIndex < )
{
MessageBox.Show("数据索引的取值范围在至0之间!","错误!",
MessageBoxButtons.OK,MessageBoxIcon.Error);
return r;
}
byte[] encrypted;
//打开要写入的文件,主要是为了保持原文件的内容不丢失
System.IO.FileStream tmpFileStream= new FileStream(filePath,
System.IO.FileMode.Open,
System.IO.FileAccess.Read,
System.IO.FileShare.None,0,true);

byte[] index = new byte[06];
//将读取的内容写到byte数组
tmpFileStream.Read(index,0,06);
tmpFileStream.Close();
//定义基本的加密转换运算
System.Security.Cryptography.ICryptoTransform Encryptor = rcCSP.CreateEncryptor(Key,IV);
System.IO.MemoryStream msEncrypt = new MemoryStream();
//在此加密转换流中,加密将从csEncrypt,加密后,结果在msEncrypt流中。
System.Security.Cryptography.CryptoStream csEncrypt = new CryptoStream(msEncrypt,
Encryptor,CryptoStreamMode.Write);
//将要加密的文本转换成UTF-6 编码,保存在tmp数组。
byte[] tmp = textConverter.GetBytes(toEncryptText);
//将tmp输入csEncrypt,将通过Encryptor来加密。
csEncrypt.Write(tmp,0,tmp.Length);
//输出到msEnctypt
csEncrypt.FlushFinalBlock();
//将流转成byte[]
encrypted = msEncrypt.ToArray();
if(encrypted.Length>0)
{
MessageBox.Show("加密后,数据长度大于KB,无法保存");
return false;
}
//得到加密后数据的大小,将结果存在指定的位置。
index[dataIndex* - ] = Convert.ToByte(Convert.ToString(encrypted.Length/8));
index[dataIndex*] = Convert.ToByte(Convert.ToString(encrypted.Length%8));
//将加密后的结果写入index(覆盖)
for(int i=0;i<encrypted.Length;i++)
index[0*(dataIndex-)++i]=encrypted[i];
//建立文件流
tmpFileStream = new FileStream(filePath,
System.IO.FileMode.Truncate,
System.IO.FileAccess.Write,
System.IO.FileShare.None,0,true);
//写文件
tmpFileStream.Write(index,0,06);
tmpFileStream.Flush();
r = true;
tmpFileStream.Close();
return r;
}
/// <summary>
/// 从一个文件中解密出一段文本,其中,这个文件是由InitBinFile建立的,并且由 EncryptToFile加密的
/// </summary>
/// <param name="filePath">要解密的文件</param>
/// <param name="dataIndex">要从哪一个块中解密</param>
/// <param name="IV">初始化向量</param>
/// <param name="Key">解密密匙</param>
/// <returns>解密后的文本</returns>
public string DecryptFromFile(string filePath,int dataIndex,byte[] IV,byte[] Key)
{
string r = "";
if(dataIndex > 0 && dataIndex < )
{
MessageBox.Show("数据索引的取值范围在至0之间!","错误!",
MessageBoxButtons.OK,MessageBoxIcon.Error);
return r;
}
byte[] decrypted;
System.IO.FileStream tmpFileStream = new FileStream(filePath,
System.IO.FileMode.Open,
System.IO.FileAccess.Read,
System.IO.FileShare.None,0,true);

System.Security.Cryptography.ICryptoTransform Decryptor = rcCSP.CreateDecryptor(Key,IV);
System.IO.MemoryStream msDecrypt = new MemoryStream();
System.Security.Cryptography.CryptoStream csDecrypt = new CryptoStream(msDecrypt,
Decryptor,CryptoStreamMode.Write);
byte[] index = new byte[06];

tmpFileStream.Read(index,0,06);
int startIndex = 0*(dataIndex-)+;
int count = index[dataIndex* - ]*8 + index[dataIndex*];
byte[] tmp = new byte[count];

Array.Copy(index,0*(dataIndex-)+,tmp,0,count);
csDecrypt.Write(tmp,0,count);
csDecrypt.FlushFinalBlock();
decrypted = msDecrypt.ToArray();
r = textConverter.GetString(decrypted,0,decrypted.Length);
tmpFileStream.Close();
return r;
}
/// <summary>
/// 将一段文本加密后保存到一个文件
/// </summary>
/// <param name="toEncryptText">要加密的文本数据</param>
/// <param name="filePath">要保存的文件</param>
/// <param name="IV">初始化向量</param>
/// <param name="Key">加密密匙</param>
/// <returns>是否加密成功</returns>
public bool EncryptToFile(string toEncryptText,string filePath,byte[] IV,byte[] Key)
{
bool r = false;
byte[] encrypted;
System.IO.FileStream tmpFileStream = new FileStream(filePath,
System.IO.FileMode.OpenOrCreate,
System.IO.FileAccess.Write,
System.IO.FileShare.None,0,true);

System.Security.Cryptography.ICryptoTransform Encryptor = rcCSP.CreateEncryptor(Key,IV);
System.IO.MemoryStream msEncrypt = new MemoryStream();
System.Security.Cryptography.CryptoStream csEncrypt = new CryptoStream(msEncrypt,
Encryptor,CryptoStreamMode.Write);

byte[] tmp = textConverter.GetBytes(toEncryptText);
csEncrypt.Write(tmp,0,tmp.Length);
csEncrypt.FlushFinalBlock();
encrypted = msEncrypt.ToArray();
tmpFileStream.Write(encrypted,0,encrypted.Length);
tmpFileStream.Flush();
r = true;
tmpFileStream.Close();
return r;
}
/// <summary>
/// 将一个被加密的文件解密
/// </summary>
/// <param name="filePath">要解密的文件</param>
/// <param name="IV">初始化向量</param>
/// <param name="Key">解密密匙</param>
/// <returns>解密后的文本</returns>
public string DecryptFromFile(string filePath,byte[] IV,byte[] Key)
{
string r = "";
byte[] decrypted;
System.IO.FileStream tmpFileStream = new FileStream(filePath,
System.IO.FileMode.Open,
System.IO.FileAccess.Read,
System.IO.FileShare.None,0,true);
System.Security.Cryptography.ICryptoTransform Decryptor = rcCSP.CreateDecryptor(Key,IV);
System.IO.MemoryStream msDecrypt = new MemoryStream();
System.Security.Cryptography.CryptoStream csDecrypt = new CryptoStream(msDecrypt,
Decryptor,CryptoStreamMode.Write);

byte[] tmp = new byte[tmpFileStream.Length];
tmpFileStream.Read(tmp,0,tmp.Length);
csDecrypt.Write(tmp,0,tmp.Length);
csDecrypt.FlushFinalBlock();
decrypted = msDecrypt.ToArray();
r = textConverter.GetString(decrypted,0,decrypted.Length);
tmpFileStream.Close();
return r;
}
/// <summary>
/// 设置加密或解密的初始化向量
/// </summary>
/// <param name="s">长度等于8的ASCII字符集的字符串</param>
public void SetIV(string s)
{
if(s.Length != 8)
{
MessageBox.Show("输入的字符串必须为长度为8的且属于ASCII字符集的字符串");
this.iv =null;
return;
}
try
{
this.iv = this.asciiEncoding.GetBytes(s);
}
catch(System.Exception)
{
MessageBox.Show("输入的字符串必须为长度为8的且属于ASCII字符集的字符串");
this.iv = null;
}
}
/// <summary>
/// 设置加密或解密的密匙
/// </summary>
/// <param name="s">长度等于6的ASCII字符集的字符串</param>
public void SetKey(string s)
{
if(s.Length != 6)
{
MessageBox.Show("输入的字符串必须为长度为6的且属于ASCII字符集的字符串");
this.key = null;
return;
}
try
{
this.key = this.asciiEncoding.GetBytes(s);
}
catch(System.Exception)
{
MessageBox.Show("输入的字符串必须为长度为6的且属于ASCII字符集的字符串");
this.key = null;
}
}
}
}

//write by wenhui.org
using System;
using System.IO;
using System.Text;
using System.Collections;

namespace PDFGenerator
{

public class PDFGenerator
{
static float pageWidth = 9.0f;
static float pageDepth = 88.0f;
static float pageMargin = 0.0f;
static float fontSize = 0.0f;
static float leadSize = 0.0f;


static StreamWriter pPDF=new StreamWriter("E:\\myPDF.pdf");

static MemoryStream mPDF= new MemoryStream();

static void ConvertToByteAndAddtoStream(string strMsg)
{
Byte[] buffer=null;
buffer=ASCIIEncoding.ASCII.GetBytes(strMsg);
mPDF.Write(buffer,0,buffer.Length);
buffer=null;
}

static string xRefFormatting(long xValue)
{
string strMsg =xValue.ToString();
int iLen=strMsg.Length;
if (iLen<0)
{
StringBuilder s=new StringBuilder();
int i=0-iLen;
s.Append(‘0′,i);
strMsg=s.ToString() + strMsg;
}
return strMsg;
}

static void Main(string[] args)
{
ArrayList xRefs=new ArrayList();
//Byte[] buffer=null;
float yPos =0f;
long streamStart=0;
long streamEnd=0;
long streamLen =0;
string strPDFMessage=null;
//PDF文档头信息
strPDFMessage="%PDF-.\n";
ConvertToByteAndAddtoStream(strPDFMessage);

xRefs.Add(mPDF.Length);
strPDFMessage=" 0 obj\n";
ConvertToByteAndAddtoStream(strPDFMessage);
strPDFMessage="<< /Length 0 R >>\n";
ConvertToByteAndAddtoStream(strPDFMessage);
strPDFMessage="stream\n";
ConvertToByteAndAddtoStream(strPDFMessage);
/**/////////PDF文档描述
streamStart=mPDF.Length;
//字体
strPDFMessage="BT\n/F0 " + fontSize +" Tf\n";
ConvertToByteAndAddtoStream(strPDFMessage);
//PDF文档实体高度
yPos = pageDepth – pageMargin;
strPDFMessage=pageMargin + " " + yPos +" Td\n" ;
ConvertToByteAndAddtoStream(strPDFMessage);
strPDFMessage= leadSize+" TL\n" ;
ConvertToByteAndAddtoStream(strPDFMessage);

//实体内容
strPDFMessage= "(http://www.wenhui.org)Tj\n" ;
ConvertToByteAndAddtoStream(strPDFMessage);
strPDFMessage= "ET\n";
ConvertToByteAndAddtoStream(strPDFMessage);
streamEnd=mPDF.Length;

streamLen=streamEnd-streamStart;
strPDFMessage= "endstream\nendobj\n";
ConvertToByteAndAddtoStream(strPDFMessage);
//PDF文档的版本信息
xRefs.Add(mPDF.Length);
strPDFMessage=" 0 obj\n"+ streamLen + "\nendobj\n";
ConvertToByteAndAddtoStream(strPDFMessage);

xRefs.Add(mPDF.Length);
strPDFMessage=" 0 obj\n<</Type/Page/Parent 0 R/Contents 0 R>>\nendobj\n";
ConvertToByteAndAddtoStream(strPDFMessage);

xRefs.Add(mPDF.Length);
strPDFMessage=" 0 obj\n<</Type /Pages /Count \n";
ConvertToByteAndAddtoStream(strPDFMessage);
strPDFMessage="/Kids[\n 0 R\n]\n";
ConvertToByteAndAddtoStream(strPDFMessage);
strPDFMessage="/Resources<</ProcSet[/PDF/Text]/Font<</F0 0 R>> >>\n";
ConvertToByteAndAddtoStream(strPDFMessage);
strPDFMessage="/MediaBox [ 0 0 "+ pageWidth + " " + pageDepth + " ]\n>>\nendobj\n";
ConvertToByteAndAddtoStream(strPDFMessage);

xRefs.Add(mPDF.Length);
strPDFMessage=" 0 obj\n<</Type/Font/Subtype/Type/BaseFont/Courier/Encoding/WinAnsiEncoding>>\nendobj\n";
ConvertToByteAndAddtoStream(strPDFMessage);

xRefs.Add(mPDF.Length);
strPDFMessage="6 0 obj\n<</Type/Catalog/Pages 0 R>>\nendobj\n";
ConvertToByteAndAddtoStream(strPDFMessage);

streamStart=mPDF.Length;
strPDFMessage="xref\n0 7\n0000000000 6 f \n";
for(int i=0;i<xRefs.Count;i++)
{
strPDFMessage+=xRefFormatting((long) xRefs[i])+" 00000 n \n";
}
ConvertToByteAndAddtoStream(strPDFMessage);
strPDFMessage="trailer\n<<\n/Size "+ (xRefs.Count+)+"\n/Root 6 0 R\n>>\n";
ConvertToByteAndAddtoStream(strPDFMessage);

strPDFMessage="startxref\n" + streamStart+"\n%%EOF\n";
ConvertToByteAndAddtoStream(strPDFMessage);
mPDF.WriteTo(pPDF.BaseStream);

mPDF.Close();
pPDF.Close();
}
}
}