《ASP.NET本质论》 页面即对象

来源:互联网 发布:淘宝使用感受 编辑:程序博客网 时间:2024/05/17 13:44

         流动的网页
              在控制台应用程序中,常用的输入输出语句为WiretLine 和ReadLine。为什么可以使用这些方法从键盘输入内容,又为什么内容会输出到屏幕上去呢?
             下面我们看一下Console对象的常用成员
               

成员

说明

In

System.IO.TextReader 类型,表示控制台的输入了

Out

System.IO.TextWriter 类型,表示控制台的输出流

Error

System.IO.TextWriter 类型,表示控制台的错误输出流

SetIn

重新设置控制台的输入流

SetOut

重新设置控制台的输出流

SetError

重新设置控制台的错误输出流


SetIn方法的定义:

public static void SetIn (TextReader newIn)

SetOut方法的定义:
public static void SetOut (TextWriter newOut)

        对于控制台来所,ReadLine 和 WriteLine 方法是通过控制台的 In 和 Out 属性设置的流进行输入和输出的。这两个属性的默认值是操作系统在启动控制台应用程序时设置的,分别指向标准输入流和标准输出流,默认就是常见的键盘和显示器。在程序中,也可以通过SetIn 和 SetOut 方法进行重新设置,我们称为输入输出的重定向。
       当一个程序启动的时候,操作系统将直接提供三个流供这个程序完成基本的输出和输入,这三个流分别是标准输入流,标准输出流和标准错误流。
       流是对输入输出的高度抽象,通常我们将用来输入信息的流称为源,源表示信息的来源,比如,键盘、文件输入、网络输入等;将用来输出信息的流程为汇,汇表示信息流向的目标,比如:显示器、打印机、文件输出、网络输出等。

        在流中,输入输出的信息排列成一个信息的序列。信息的基本单位在不同的流中是不同的,基本单位是字节的流称为字节流,基本单位是字符的流程为字符流,基本单位是Xml节点的流就是Xml流。

        字节流
             在信息处理中,最基本的单位是二进制的位(bit),但是这个单位太小了,所以常常使用8位组(Octec)或者字节(byte)作为基本单位。从道理是讲,一个字节不一定是8位,但是,在现代的计算机系统中,事实标准就是使用8位来表示一个字节。所以,在后面的介绍中,我们也就沿用大家所熟悉的“字节”这个概念。
             在基于流的输入输出中,最基本的就是基于字节的输入和输出。
             在.NET中,System.IO 命名空间中的Stream定义了基于字节的输入和输出的基类,这是一个抽象类,定义如下:
                   

[SerializableAttribute][ComVisibleAttribute(true)]public abstract class Stream : MarshalByRefObject, IDisposable
                从流中读取一个字节的方法为ReadByte,定义如下:
                                
public virtual int ReadByte()

从流中读取一个字节,并将流内的位置向前推进一个字节,如果已到达流的末尾,则返回 -1。

ReadByte一次只呢个读取一个字节。我们经常使用的输入方法为Read,Read方法可以一次读取多个字节,定义如下:
public abstract int Read(byte[] buffer,int offset,int count)

              Read方法从流中以字节块的方式读取信息,读取的内容将保存到buffer指向的字节数组中保存在数组中从offset下表开始的位置,count表示从流中最多希望读取的字节数量,方法的返回值为实际从流中读取的字节数量。如果返回值为0,则表示流中已经没有内容可以读了。
             主要的输出方法为Write,方法的定义如下:
public abstract void Write(byte[] buffer,int offset,int count)

表示将一组字节数据写入流总,数据保存在buffer指向的字节数组中,从offset指定的下表开始,count表示从offset开始的字节数量,这些信息将写入到流中。
              在.NET下,有多个派生类派生自 Stream,如下说是:
System.IO.Stream      Microsoft.JScript.COMCharStream      System.Data.OracleClient.OracleBFile      System.Data.OracleClient.OracleLob      System.Data.SqlTypes.SqlFileStream      System.IO.BufferedStream      System.IO.Compression.DeflateStream      System.IO.Compression.GZipStream      System.IO.FileStream      System.IO.MemoryStream      System.IO.Pipes.PipeStream      System.IO.UnmanagedMemoryStream      System.Net.Security.AuthenticatedStream      System.Net.Sockets.NetworkStream      System.Printing.PrintQueueStream      System.Security.Cryptography.CryptoStream

         对于常用的磁盘文件来说,我们可以使用FileStream进行操作。例如,下面的例子是一文件流打开一个文件,然后在控制台输出其内容。
             
System.IO.FileStream stream = new System.IO.FileStream("../../phone.txt", System.IO.FileMode.Open);            byte[] buffer = new byte[4096];            int length = 0;            while ((length = stream.Read(buffer, 0, 4096)) > 0)            {                Console.WriteLine(BitConverter.ToString(buffer, 0, length));            }            stream.Close();            Console.ReadLine();

         还有一些类内部封装了针对字节流的操作,以便简化编程的负担。例如,System.IO.File类就提供了许多静态方法,允许我们直接以字节的方式对文件进行读写。
         ReadAllBytes方法提供了直接读取文件的操作,方法的定义如下:
                 
public static byte[] ReadAllBytes (string path)
         这样的话,上面的例子就可以更加简单的如下完成了:
 byte[] buffer= System.IO.File.ReadAllBytes("../../phone.txt");            Console.WriteLine(BitConverter.ToString(buffer));            Console.ReadLine();




           字符编码
                 对于网页来说,我们通常并不需要处理字节那么底层,我们需要的是输出字符串组成的网页。通过建立人使用的字符与计算机处理的数字之间的对应关系,我们创建了字符编码表。通过字符编码表,我们可以查出字符对应的数字,也可以反向查出数字对应的字符。
                现在在世界上,同时存在着许多字符编码表,常见的英文字符表为ASCII编码表,对于简体中文来说,GB2312字符表定义了常用汉字的编码,Unicode编码定义了一个包含目前人类使用的所以字符的巨大编码表。
               在 .NET 环境下,使用定义在 System.Text 命名空间中的 Encoding类来表示不同的编码。
                      
[SerializableAttribute][ComVisibleAttribute(true)]public abstract class Encoding : ICloneable

             这个抽象类提供了GetEncoding静态方法来获取特定的编码表对象。
public static Encoding GetEncoding(int codepage)

public static Encoding GetEncoding(string name)

using System;using System.Text;public class SamplesEncoding  {   public static void Main()  {      // Get a UTF-32 encoding by codepage.      Encoding e1 = Encoding.GetEncoding( 12000 );      // Get a UTF-32 encoding by name.      Encoding e2 = Encoding.GetEncoding( "utf-32" );      // Check their equality.      Console.WriteLine( "e1 equals e2? {0}", e1.Equals( e2 ) );   }}/* This code produces the following output.e1 equals e2? True*/

              其中name为编码方法的名称,codepage为编码方案的编号,也成为代码页(Code Page)。特殊的编号 0  用来特质当前系统的默认编码。对于简体中文来说,代码也为936,编码的名称为:GB2312
              代码页容易被计算机处理,但是不容易被人记忆和使用。通常我们使用编码的名称,编码的名称来自IANA,通过Encoding对象的WebName属性可以取得这个名称。
public virtual string WebName { get; }

static void Main(string[] args)        {            Encoding encoding = System.Text.Encoding.GetEncoding(0);            Console.WriteLine(encoding.WebName);// gb2312            Console.ReadLine();        }

           取得字符编码之后,通过字符编码,我们可以将字符编码为对应的数字,以自己方式进行输入和输出。通过编码对象的GetString方法可以将字节格式的数字重新解码为字符,相对应地,GetBytes方法允许我们将字符编码为字节格式的数字。通过这两个方法,我们就可以在程序中进行字符编码和转换操作。
            byte[] buffer =System.IO.File.ReadAllBytes("../../phone.txt");                        Encoding encoding = System.Text.Encoding.GetEncoding(0);            

string s=encoding.GetString(buffer); Console.WriteLine(s); byte[] gbbytes = Encoding.UTF8.GetBytes(s); System.IO.File.WriteAllBytes("../../aa.txt", gbbytes); Console.ReadLine();


            字符流
                   为了便于以流的方式操作字符,在 .NET中也提供了字符流。字符流对象内部直接包含了一个字符编码对象,使得我们可以直接使用字符的方式进行输入和输出,更加简便地完成字符与数字之间的转换工作。对于字符流来说,没有既支持输入又支持输出的字符流。基于字符的流被分为两大类:字符输入流和字符输出流。

                  字符输出流
                  需要注意的是,字节和字符是完全不同的两种数据类型,可以看到,字符输出流并不从字节流中派生,虽然它内部使用了字节流。
                  字符输出流提供了一个抽象基类,定义如下:
                     
[SerializableAttribute] [ComVisibleAttribute(true)] public abstract class TextWriter : MarshalByRefObject, IDisposable

其中包含了一个字符编码的属性 Encoding。这个属性是只读的,只能在构造的时候进行设置。
public abstract Encoding Encoding { get; }
其中常用的方法为输出一个字符。
WriteLine 已重载。 写入重载参数指定的某些数据,后跟行结束符。 

               WriteLine表示输出一行字符,format为格式化串,arg为格式化船中所使用的参数。在输出字符的过程中,字符输出流通过编码将字符编码为相应的数字,然后通过字节流进行输出。
               它常用的两个派生类如下:
                   System.IO.StreamWriter     //基于文件的字符输出
                   System.IO.StringWriter         //基于内存的字符输出
              字符输入流
               字符输入流同样也有一个抽象基类,定义如下:
               public abstract class TextReader : MarshalByRefObject , IDisposable

               对于字符输入流来说,并没有一个可以直接访问到的Enconding属性,但是,在字符流输入流的内部也存在一个编码对象,这个编码对象只能在创建字符输入流对象实例的时候传递进去。
                其中常用的方法如下:
                      public virtual string ReadLine()
              表示从流中读取一个字符。
             它的两个主要派生类如下:
              System.IO.StreamReader //从文件中读取字符
              System.IO.StringReader  //从字符串中读取字符
                    使用字符流,我们可以更加简单地完成上面的字符编码转换操作。
              控制台的流就是文本流,输入输出为TextReader类型,输出流为TextWriter类型。
              
string s = "aaaaaaaaaaaaaaaaaaaaaaaaa";            System.IO.TextWriter writer = Console.Out;            writer.WriteLine(s);

                 

            回应对象中的流
            所谓网站应用程序,就是指程序的输入和输出来自客户端的浏览器。如果我们能够取得来自于浏览器的输入流和指向浏览器的输出流,就可以将网站应用程序类似于普通的控制台程序进行处理,通过向字符串输出流中写入HTML的文本内容来使程序生成网页。
           在网站中,HttpContext对象的Response属性指向表示输出的HttpResponse类型的对象实例,HttpResponse中的OutputStream就是指向浏览器的字节输出流。
           多数是情况下,我们需要向浏览器输出字符,HttpResponse的Output属性表示指向浏览器的字符流,这个流所使用的字符编码由HttpResponse对象的ContentEncoding属性指定。这个属性的定义如下:
           public encoding ContentEncoding {get; set;}
           回应对象使用的文本输出流的实际类型定义在System.Web命名空间下,类型为HttpWriter,它使得通过HttpResponse输出网页变得更加方便。
                public sealed class HttpWriter : TextWriter
          所以,如果希望通过HttpResponse 对象数一段HTML,那么可以如下完成:
               
protected void Page_Load(object sender, EventArgs e)        {            string div = "<div><input type='button' value='input'/> </div>";            System.IO.TextWriter writer = Response.Output;            writer.Write(div);        }

           专门输出HTML哦字符流
            HTML是一种标记语言,这种语言定义了大量的标记,这些标记在 .NET 中以枚举的方式进行了定义,这个定义在命名空间System.Web.UI中。
          
                 public enum HtmlTextWriterTag

           与之配合,为了能够更加方便地输出HTML字符,在System.Web.UI命名空间下,还定义了一系列专门输出HTML字符的字符流。这些字符流的基类为TextWriter,定义如下:
           
                public clas HtmlTextWriter : TextWriter

          它有三个派生类。
                 System.Web.UI.Html32TextWriter
                 System.Web.UI.MobileControls.Adapters.MultiPartWriter
                 System.Web.UI.XhtmlTextWriter

          System.Web.UI.MobileControls 命名空间用于移动设备,对于MultiPartWriter来说,定义在命名空间System.Web.UI.MobileControls.Adapters 下的派生类 MobileTextWriter 用来生产移动设备使用的HTML 。
          Html32TextWriter 用来生成 HTML 3 .2 标准的网页。
          对于普通的网页来说,我们主要使用XhtmlTextWriter生成符合XHTML规范的网页。
          注意一下XhtmlTextWriter的构造函数,可以看到它的内部使用字符输出流来完成实际的字符输出。

                     
public XhtmlTextWriter(TextWriter writer)

         对于上一节中的HTML,可以使用XhtmlTextWriter如下生成:
         
System.IO.TextWriter writer=Response.Output;            System.Web.UI.XhtmlTextWriter inputtag = new XhtmlTextWriter(writer);            inputtag.WriteFullBeginTag("div");            inputtag.WriteBeginTag("input");            inputtag.WriteAttribute("type", "button");            inputtag.WriteAttribute("value","input");            inputtag.Write(HtmlTextWriter.TagRightChar);            inputtag.WriteEndTag("input");            inputtag.WriteEndTag("div");
        有一个地方比较有趣,XhtmlTextWriter的WriterFullBeginTag将生成一个包含 > 的开始标记,而WriterBeginTag则不会生产,这样有助于我们为这个开始标记继续生成一些属性,但是在属性生成之后,必须手工增加这个结束 > 符号,这个符号定义在HtmlTextWriter 的TagRightChar属性中。
        配合HtmlTextWriterTag枚举,HtmlTextWriter还提供了RenderXXX方法,这样我们不可能由于拼写的问题写出不正确的标记名了。上面的代码还可以如下实现:
         
protected void Page_Load(object sender, EventArgs e)        {            System.IO.TextWriter writer=Response.Output;            System.Web.UI.XhtmlTextWriter inputtag = new XhtmlTextWriter(writer);                        inputtag.RenderBeginTag(HtmlTextWriterTag.Div);                        inputtag.AddAttribute(HtmlTextWriterAttribute.Type, "button");            inputtag.AddAttribute(HtmlTextWriterAttribute.Value, "input");            inputtag.RenderBeginTag(HtmlTextWriterTag.Input);            inputtag.RenderEndTag();        }


          在使用RenderBeginTag的时候,需要先定义属性,然后再生成标记。