Delphi TStream 详细介绍
Stream对象,又称流式对象,是TStream、THandleStream、TFileStream、TMemoryStream、TResourceStream和TBlobStream等的统称。它们分别代表了在各种媒介上存储数据的能力,它们将各种数据类型(包括对象和部件)  
在内存、外存和数据库字段中的管理操作抽象为对象方法,并且充分利用了面向对象技术的优点,应用程序可以相当容易地在各种Stream对象中拷贝数据。 
  下面介绍各种对象的数据和方法及使用方法。 
TStream对象

  TStream对象是能在各种媒介中存储二进制数据的对象的抽象对象。从TStream 对象继承的对象用于在内存、Windows资源文件、磁盘文件和数据库字段等媒介中存储数据。 
  Stream中定义了两个属性:Size和Position。它们分别以字节为单位表示的流的大小和当前指针位置。TStream中定义的方法用于在各种流中读、写和相互拷贝二进制数据。因为所有的Stream对象都是从TStream中继承来的,所以在TStream中定义的域和方法都能被Stream对象调用和访 
问。此外,又由于面向对象技术的动态联编功能,TStream为各种流的应用提供了统一的接口,简化了流的使用;不同Stream对象是抽象了对不同存储媒介的数据上的操作,因此,TStream的需方法为在不同媒介间的数据拷贝提供了最简捷的手段。

TStream的属性和方法

  1. Position属性  
     声明:property Position: Longint;  
  Position属性指明流中读写的当前偏移量。 
  2. Size属性 
  声明:property Size: Longint;  
     Size属性指明了以字节为单位的流的的大小,它是只读的。 
  3. CopyFrom方法 
  声明:function CopyFrom(Source: TStream; Count: Longint): Longint;  
     CopyFrom从Source所指定的流中拷贝Count个字节到当前流中, 并将指针从当前位置移动Count个字节数,函数返回值是实际拷贝的字节数。 
  4. Read方法 
  声明:function Read(var Buffer; Count: Longint): Longint; virtual; abstract;  
     Read方法从当前流中的当前位置起将Count个字节的内容复制到Buffer中,并把当前指针向后移动Count个字节数,函数返回值是实际读的字节数。如果返回值小于Count,这意味着读操作在读满所需字节数前指针已经到达了流的尾部。 
  Read方法是抽象方法。每个后继Stream对象都要根据自己特有的有关特定存储媒介的读操作覆盖该方法。而且流的所有其它的读数据的方法(如:ReadBuffer,ReadComponent等)在完成实际的读操作时都调用了Read方法。面向对象的动态联编的优点就体现在这儿。因为后继Stream对 象只需覆盖Read方法,而其它读操作(如ReadBuffer、ReadComponent等)都不需要重新定义,而且TStream还提供了统一的接口。 
  5. ReadBuffer方法 
  声明:procedure ReadBuffer(var Buffer; Count: Longint);  
  ReadBuffer方法从流中将Count个字节复制到Buffer 中, 并将流的当前指针向后移动Count个字节。如读操作超过流的尾部,ReadBuffer方法引起EReadError异常事件。 
  6. ReadComponent方法 
  声明:function ReadComponent(Instance: TComponent): TComponent;  
     ReadComponent方法从当前流中读取由Instance所指定的部件,函数返回所读的部件。ReadComponent在读Instance及其拥有的所有对象时创建了一个Reader对象并调用它的ReadRootComponent方法。 
  如果Instance为nil,ReadComponent的方法基于流中描述的部件类型信息创建部件,并返回新创建的部件。 
  7. ReadComponentRes方法 
  声明:function ReadComponentRes(Instance: TComponent): TComponent;  
     ReadComponentRes方法从流中读取Instance指定的部件,但是流的当前位置必须是由WriteComponentRes方法所写入的部件的位置。 
  ReadComponentRes  
首先调用ReadResHeader方法从流中读取资源头,然后调用ReadComponent方法读取Instance。如果流的当前位置不包含一个资源头。ReadResHeader将引发一个EInvalidImage异常事件。在Classes库单元中也包含一个名为ReadComponentRes的函数,该函数执行相同的操作,只不过它基于应 
用程序包含的资源建立自己的流。 
  8. ReadResHeader方法 
  声明:procedure ReadResHeader;  
     ReadResHeader方法从流的当前位置读取Windows资源文件头,并将流的当前位置指针移到该文件头的尾部。如果流不包含一个有效的资源文件头,ReadResHeader将引发一个EInvalidImage异常事件。 
  流的ReadComponentRes方法在从资源文件中读取部件之前,会自动调用ReadResHeader方法,因此,通常程序员通常不需要自己调用它。 
  9. Seek方法 
  声明:function Seek(Offset: Longint; Origin: Word): Longint; virtual; abstract;  
     Seek方法将流的当前指针移动Offset个字节,字节移动的起点由Origin指定。如果Offset是负数,Seek方法将从所描述的起点往流的头部移动。下表中列出了Origin的不同取值和它们的含义:

函数Seek的参数的取值 
 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 
  常量       值      Seek的起点         Offset的取值 
   ───────────────────────────────── 
 SoFromBeginning     0            流的开头              正 数 
 SoFromCurrent       1              流的当前位置        正数或负数   
 SoFromEnd          2              流的结尾              负 数 
 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 
                   
    10. Write方法 
  在Delphi对象式管理的对象中有两类对象的方法都有称为Write的:Stream对象和Filer对象。Stream对象的Write方法将数据写进流中。Filer对象通过相关的流传递数据,在后文中会介绍这类方法。 
  Stream对象的Write方法声明如下:

function Write(const Buffer; Count: Longint): Longint; virtual; abstract;

Write方法将Buffer中的Count个字节写入流中,并将当前位置指针向流的尾部移动Count个字节,函数返回写入的字节数。 
    TStream的Write方法是抽象的,每个继承的Stream对象都要通过覆盖该方法来提供向特定存储媒介(内存、磁盘文件等)写数据的特定方法。流的其它所有写数据的方法(如WriteBuffer、WriteComponent)都调用Write担当实际的写操作。 
  11. WriteBuffer方法 
  声明:procedure WriteBuffer(const Buffer; Count: Longint);  
  WriteBuffer的功能与Write相似。WriteBuffer方法调用Write来执行实际的写操作,如果流没能写所有字节,WriteBuffer会触发一个EWriteError异常事件。 
  12. WriteComponent方法 
  在Stream对象和Filer对象都有被称为WriteComponent的方法。Stream对象的WriteComponent方法将Instance所指定的部件和它所包含的所有部件都写入流中;Writer对象的WriteComponent将指定部件的属性值写入Writer对象的流中。 
  Stream对象的WriteComponent方法声明是这样的: 
        procedure WriteComponent(Instance: Tcomponent);

  WriteComponent创建一个Writer对象,并调用Writer的WriteRootComponent方法将Instance及其拥有的对象写入流。 
  13. WriteComponentRes方法 
  声明:WriteComponentRes(const ResName: String; Instance: TComponent);  
  WriteComponentRes方法首先往流中写入标准Windows 资源文件头,然后将Instance指定的部件写入流中。要读由WriteComponentRes写入的部件,必须调用ReadComponentRes方法。 
  WriteComponentRes使用ResName传入的字符串作为资源文件头的资源名,然后调用WriteComponent方法将Instance和它拥有的部件写入流。 
  14. WriteDescendant方法 
  声明:procedure WriteDescendant(Instance Ancestor: TComponent);  
  Stream对象的WriteDescendant方法创建一个Writer对象,然后调入该对象的WriteDescendant方法将Instance部件写入流中。Instance可以是从Ancestor部件继承的窗体,也可以是在从祖先窗体中继承的窗体中相应于祖先窗体中Ancestor部件的部件。 
  15. WriteDescendantRes方法 
  声明:procedure WriteDescendantRes(const ResName: String; 
                                         Instance, Ancestor: TComponent); 
  WriteDescendantRes方法将Windows资源文件头写入流,并使用ResName作用资源名,然后调用WriteDescendant方法,将Instance写入流。

TStream的实现原理

  TStream对象是Stream对象的基础类,这是Stream对象的基础。为了能在不同媒介上的存储数据对象,后继的Stream对象主要是在Read和Write方法上做了改进,。因此,了解TStream是掌握Stream对象管理的核心。Borland公司虽然提供了Stream对象的接口说明文档,但对于其实现和应 
用方法却没有提及,笔者是从Borland Delphi 2.0 Client/Server Suite 提供的源代码和部分例子程序中掌握了流式对象技术。 
  下面就从TStream的属性和方法的实现开始。 
  1. TStream属性的实现 
  前面介绍过,TStream具有Position和Size两个属性,作为抽象数据类型,它抽象了在各种存储媒介中读写数据所需要经常访问的域。那么它们是怎样实现的呢? 
  在自定义部件编写这一章中介绍过部件属性定义中的读写控制。Position和Size也作了读写控制。定义如下:

property Position: Longint read GetPosition write SetPosition; 
     property Size: Longint read GetSize;

  由上可知,Position是可读写属性,而Size是只读的。 
  Position属性的实现就体现在GetPosition和SetPosition。当在程序运行过程中,任何读取Position的值和给Position赋值的操作都会自动触发私有方法GetPosition和SetPosition。两个方法的声明如下:

function TStream.GetPosition: Longint; 
     begin 
       Result := Seek(0, 1); 
     end;

procedure TStream.SetPosition(Pos: Longint); 
     begin 
       Seek(Pos, 0); 
     end;

在设置位置时,Delphi编译机制会自动将Position传为Pos。 
  前面介绍过Seek的使用方法,第一参数是移动偏移量,第二个参数是移动的起点,返回值是移动后的指针位置。 
  Size属性的实现只有读控制,完全屏蔽了写操作。读控制方法GetSize实现如下:

function TStream.GetSize: Longint; 
     var 
       Pos: Longint; 
     begin 
       Pos := Seek(0, 1); 
       Result := Seek(0, 2); 
       Seek(Pos, 0); 
     end;

2. TStream方法的实现 
  ⑴ CopyFrom方法 
  CopyFrom是Stream对象中很有用的方法,它用于在不同存储媒介中拷贝数据。例如,内存与外部文件之间、内存与数据库字段之间等。它简化了许多内存分配、文件打开和读写等的细节,将所有拷贝操作都统一到Stream对象上。 
  前面曾介绍:CopyFrom方法带Source和Count两个参数并返回长整型。该方法将Count个字节的内容从Source拷贝到当前流中,如果Count值为0则拷贝所有数据。

function TStream.CopyFrom(Source: TStream; Count: Longint): Longint; 
     const 
       MaxBufSize = $F000; 
     var 
       BufSize, N: Integer; 
       Buffer: PChar; 
     begin 
       if Count = 0 then 
       begin 
         Source.Position := 0; 
         Count := Source.Size; 
       end; 
       Result := Count; 
       if Count > MaxBufSize then BufSize := MaxBufSize else BufSize := Count; 
       GetMem(Buffer, BufSize); 
       try 
         while Count <> 0 do 
         begin 
           if Count > BufSize then  
             N := BufSize  
           else 
             N := Count; 
           Source.ReadBuffer(Buffer^, N); 
           WriteBuffer(Buffer^, N); 
           Dec(Count, N); 
         end; 
       finally 
         FreeMem(Buffer, BufSize); 
       end; 
     end;

  ⑵ ReadBuffer方法和WriteBuffer方法 
  ReadBuffer方法和WriteBuffer方法简单地调用虚拟函数Read、Write来读写流中数据,它比Read和Write增加了读写数据出错时的异常处理。

procedure TStream.ReadBuffer(var Buffer; Count: Longint); 
     begin 
       if (Count <> 0) and (Read(Buffer, Count) <> Count) then 
         raise EReadError.CreateRes(SReadError); 
     end;

procedure TStream.WriteBuffer(const Buffer; Count: Longint); 
     begin 
       if (Count <> 0) and (Write(Buffer, Count) <> Count) then 
         raise EWriteError.CreateRes(SWriteError); 
     end;

  ⑶ ReadComponent、ReadResHeader和ReadComponentRes方法 
  ReadComponent方法从当前流中读取部件。在实现上ReadComponent方法创建了一个TStream对象,并用TReader的ReadRootComponent方法读部件。在Delphi对象式管理中,Stream对象和Filer对象结合很紧密。Stream对象的许多方法的实现需要Filer对象的支持,而Filer对象的构造函数 
直接就以Stream对象为参数。在ReadComponent方法的实现中就可清楚地看到这一点:

function TStream.ReadComponent(Instance: TComponent): TComponent; 
     var 
       Reader: TReader; 
     begin 
       Reader := TReader.Create(Self, 4096); 
       try 
         Result := Reader.ReadRootComponent(Instance); 
       finally 
         Reader.Free; 
       end; 
     end;

ReadResHeader方法用于读取Windows资源文件的文件头,由ReadComponentRes方法在读取Windows资源文件中的部件时调用,通常程序员不需自己调用。如果读取的不是资源文件ReadResH := FSize + Offset; 
           end; 
           Result := FPosition; 
         end;

  Offse代表移动的偏移量。Origin代表移动的起点,值为0表示从文件头开始,值为1表示从当前位置开始,值为2表示从文件尾往前,这时OffSet一般为负数。Seek的实现没有越界的判断。 
  3. SaveToStream和SaveToFile方法 
  SaveToStream方法是将MemoryStream对象中的内容写入Stream所指定的流。其实现如下:

procedure TCustomMemoryStream.SaveToStream(Stream: TStream); 
         begin 
           if FSize <> 0 then Stream.WriteBuffer(FMemory^, FSize); 
         end;

  SaveToStream方法调用了Stream的WriteBuffer方法,直接将FMemory中的内容按FSize字节长度写入流中。 
  SaveToFile方法是与SaveToStream方法相关的。SaveToFile方法首先创建了一个FileStream对象,然后把该文件Stream对象作为SaveToStream的参数,由SaveToStream 方法执行写操作,其实现如下:

procedure TCustomMemoryStream.SaveToFile(const FileName: string); 
         var 
           Stream: TStream; 
         begin 
           Stream := TFileStream.Create(FileName, fmCreate); 
           try 
             SaveToStream(Stream); 
           finally 
             Stream.Free; 
           end; 
         end;

  在Delphi 的许多对象的SaveToStream 和SaveToFile、LoadFromStream和LoadFromFile方法的实现都有类似的嵌套结构。

TMemoryStream对象

    
TMemoryStream对象是一个管理动态内存中的数据的Stream对象,它是从TCustomMemoryStream中继承下来的,除了从TCustomMemoryStream中继承的属性和方法外,它还增加和覆盖了一些用于从磁盘文件和其它注台读数据的方法。它还提供了写入、消除内存内容的动态内存管理方法。下面 
介绍它的这些属性和方法。

TMemoryStream的属性和方法

  1. Capacity属性 
  声明:property Copacity: Longint;  
     Capacity属性决定了分配给内存流的内存池的大小。这与Size属性有些不同。Size属性是描述流中数据的大小。在程序中可以将Capacity 的值设置的比数据所需最大内存大一些,这样可以避免频繁地重新分配。 
  2. Realloc方法 
  声明:function Realloc(var NewCapacity: Longint): Pointer; virtual;  
     Realloc方法,以8K为单位分配动态内存,内存的大小由NewCapacity指定,函数返回指向所分配内存的指针。 
  3. SetSize方法 
  SetSize方法消除内存流中包含的数据,并将内存流中内存池的大小设为Size字节。如果Size为零,是SetSize方法将释放已有的内存池,并将Memory属性置为nil;否则,SetSize方法将内存池大小调整为Size。 
     4. Clear方法 
  声明:procedure Clear;  
     Clear方法释放内存中的内存池,并将Memory属性置为nil。在调用Clear方法后,Size和Position属性都为0。 
  5. LoadFromStream方法 
  声明:procedure LoadFromStream(Stream: TStream);  
     LoadFromStream方法将Stream指定的流中的全部内容复制到MemoryStream中,复制过程将取代已有内容,使MemoryStream成为Stream的一份拷贝。 
  6. LoadFromFile方法 
  声明:procedure LoadFromFile(count FileName: String);  
     LoadFromFile方法将FileName指定文件的所有内容复制到MemoryStream中,并取代已有内容。调用LoadFromFile方法后,MemoryStream将成为文件内容在内存中的完整拷贝。

TMemoryStream对象的实现原理

  TMemoryStream从TCustomMemoryStream对象直接继承,因此可以享用TCustomMemoryStream的属性和方法。前面讲过,TCustomMemoryStream是用于内存中数据操作的抽象对象,它为MemoryStream对象的实现提供了框架,框架中的内容还要由具体MemoryStream对象去填充。TMemoryStrea 
m对象就是按动态内存管理的需要填充框架中的具体内容。下面介绍TMemoryStream对象的实? FBuffer := AllocMem(FDataSet.RecordSize); 
               FRecord := FBuffer; 
               if not FDataSet.GetCurrentRecord(FBuffer) then Exit; 
               OpenMode := dbiReadOnly; 
         end else 
             begin 
               if not (FDataSet.State in [dsEdit, dsInsert]) then DBError(SNotEditing); 
               OpenMode := dbiReadWrite; 
             end; 
             Check(DbiOpenBlob(FDataSet.Handle, FRecord, FFieldNo, OpenMode)); 
           end; 
           FOpened := True; 
           if Mode = bmWrite then Truncate; 
         end;

 该方法首先是用传入的Field参数给FField,FDataSet,FRecord和FFieldNo赋值。方法中用AllocMem按当前记录大小分配内存,并将指针赋给FBuffer,用DataSet部件的GetCurrentRecord方法,将记录的值赋给FBuffer,但不包括BLOB数据。 
  方法中用到的DbiOpenBlob函数是BDE的API函数,该函数用于打开数据库中的BLOB字段。 
  最后如果方法传入的Mode参数值为bmWrite,就调用Truncate将当前位置指针以后的 
数据删除。 
  分析这段源程序不难知道: 
  ● 读写BLOB字段,不允许BLOB字段所在DataSet部件有Filter,否则产生异常事件 
  ● 要读写BLOB字段,必须将DataSet设为编辑或插入状态 
  ● 如果BLOB字段中的数据作了修改,则在创建BLOB 流时,不再重新调用DBiOpenBlob函数,而只是简单地将FOpened置为True,这样可以用多个BLOB 流对同一个BLOB字段读写

  Destroy方法释放BLOB字段和为FBuffer分配的缓冲区,其实现如下:

destructor TBlobStream.Destroy; 
         begin 
           if FOpened then 
           begin 
             if FModified then FField.FModified := True; 
             if not FField.FModified then 
               DbiFreeBlob(FDataSet.Handle, FRecord, FFieldNo); 
           end; 
           if FBuffer <> nil then FreeMem(FBuffer, FDataSet.RecordSize); 
           if FModified then 
           try 
             FField.DataChanged; 
           except 
             Application.HandleException(Self); 
           end; 
         end;

  如果BLOB流中的数据作了修改,就将FField的FModified置为True;如果FField的Modified为False就释放BLOB字段,如果FBuffer不为空,则释放临时内存。最后根据FModified的值来决定是否启动FField的事件处理过程DataChanged。 
  不难看出,如果BLOB字段作了修改就不释放BLOB字段,并且对BLOB 字段的修改只有到Destroy时才提交,这是因为读写BLOB字段时都避开了FField,而直接调用BDE API函数。这一点是在应用BDE API编程中很重要,即一定要修改相应数据库部件的状态。 
  2. Read和Write方法的实现 
  Read和Write方法都调用BDE API函数完成数据库BLOB字段的读写,其实现如下: 
   
         function TBlobStream.Read(var Buffer; Count: Longint): Longint; 
         var 
           Status: DBIResult; 
         begin 
           Result := 0; 
           if FOpened then 
           begin 
             Status := DbiGetBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition, 
                                                            Count, @Buffer, Result); 
             case Status of 
               DBIERR_NONE, DBIERR_ENDOFBLOB: 
                 begin 
                   if FField.FTransliterate then 
                     NativeToAnsiBuf(FDataSet.Locale, @Buffer, @Buffer, Result); 
                   Inc(FPosition, Result); 
                 end; 
               DBIERR_INVALIDBLOBOFFSET: 
                 {Nothing}; 
             else 
               DbiError(Status); 
             end; 
           end; 
         end;

  Read方法使用了BDE  
API的DbiGetBlob函数从FDataSet中读取数据,在本函数中,各参数的含义是这样的:FDataSet.Handle代表DataSet的BDE句柄,FReacord表示BLOB字段所在记录,FFieldNo表示BLOB字段号,FPosition表示要读的的数据的起始位置,Count表示要读的字节数,Buffer是读出数据所占的内存, 
Result是实际读出的字节数。该BDE函数返回函数调用的错误状态信息。 
  Read方法还调用了NativeToAnsiBuf进行字符集的转换。

function TBlobStream.Write(const Buffer; Count: Longint): Longint; 
         var 
           Temp: Pointer; 
         begin 
           Result := 0; 
           if FOpened then 
           begin 
             if FField.FTransliterate then 
             begin 
               GetMem(Temp, Count); 
               try 
                 AnsiToNativeBuf(FDataSet.Locale, @Buffer, Temp, Count); 
                 Check(DbiPutBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition, 
                   Count, Temp)); 
               finally 
                 FreeMem(Temp, Count); 
               end; 
             end else 
               Check(DbiPutBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition, 
                                                       Count, @Buffer)); 
             Inc(FPosition, Count); 
             Result := Count; 
             FModified := True; 
           end; 
         end;

Write方法调用了BDE API的DbiPutBlob函数实现往数据库BLOB字段存储数据。 
     该函数的各参数含义如下:

调用函数DbiPutBlob的各传入参数的含义 
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 
      参数名           含义 
     ────────────────────────────── 
       FDataSetHandle            写入的数据库的BDE句柄 
       FRecord                   写入数据的BLOB字段所在的记录 
        FFieldNo                  BLOB字段号 
        FPosition                  写入的起始位置 
       Count                     写入的数据的字节数 
        Buffer                     所写入的数据占有的内存地址 
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

标志,该标志意味着后面存储有一连串的项目。Reader对象,在读这一连串项目时先调用ReadListBegin方法读取该标志位,然后用EndOfList判断是否列表结束,并用循环语句读取项目。在调用WriteListBegin方法的后面必须调用WriteListEnd方法写列表结束标志,相应的在Reader对象中 
有ReadListEnd方法读取该结束标志。 
  5. WriteListEnd方法 
  声明:procedure WriteListEnd;  
     WriteListEnd方法在流中,写入项目列表结束标志,它是与WriteListBegin相匹配的方法。 
  6. WriteBoolean方法 
  声明:procedure WriteBoolean(Value: Boolean);  
     WriteBoolean方法将Value传入的布尔值写入流中。 
  7. WriteChar方法 
  声明:procedure WriteChar(Value: char);  
     WriteChar方法将Value中的字符写入流中。 
  8. WriteFloat方法 
  声明:procedure WriteFloat(Value: Extended);  
     WriteFloat方法将Value传入的浮点数写入流中。 
  9. WriteInteger方法 
  声明:procedure WriteInteger(Value: Longint);  
     WriteInteger方法将Value中的整数写入流中。 
  10. WriteString方法 
  声明:procedure WriteString(const Value: string);  
     WriteString方法将Value中的字符串写入流中。 
  11. WriteIdent方法 
  声明:procedure WriteIdent(const Ident: string);  
     WriteIdent方法将Ident传入的标识符写入流中。 
  12. WriteSignature方法 
  声明:procedure WriteSignature;  
     WriteSignature方法将Delphi Filer对象标签写入流中。WriteRootComponent方法在将部件写入流之前先调用WriteSignature方法写入Filer标签。Reader对象在读部件之前调用ReadSignature方法读取该标签以指导读操作。 
  13. WritComponent方法 
  声明:procedure WriteComponent(Component: TComponent);  
     WriteComponent方法调用参数Component的WriteState方法将部件写入流中。在调用WriteState之前,WriteComponent还将Component的ComponetnState属性置为csWriting。当WriteState返回时再清除csWriting. 
     14. WriteRootComponent方法 
  声明:procedure WriteRootComponent(Root: TComponent);  
     WriteRootComponent方法将Writer对象Root属性设为参数Root带的值,然后调用WriteSignature方法往流中写入Filer对象标签,最后调用WriteComponent方法在流中存储Root部件。

http://blog.csdn.net/tercel99/article/details/5540991

Delphi TStream 详细介绍的更多相关文章

  1. [No0000A7]批处理经常用到的变量及批处理>NUL详细介绍

    绝对路径是指调用绝对的程序位置的路径,例如: start C:\Windows\test.exe 相对路径是文件改变路径以后还会按照变量的路径所在位置去调用,例如: start %WINDIR%\te ...

  2. linux配置网卡IP地址命令详细介绍及一些常用网络配置命令

    linux配置网卡IP地址命令详细介绍及一些常用网络配置命令2010-- 个评论 收藏 我要投稿 Linux命令行下配置IP地址不像图形界面下那么方 便,完全需要我们手动配置,下面就给大家介绍几种配置 ...

  3. _MSC_VER详细介绍

    _MSC_VER详细介绍 转自:http://www.cnblogs.com/braver/articles/2064817.html _MSC_VER是微软的预编译控制. _MSC_VER可以分解为 ...

  4. php CGI、Fastcgi、PHP-FPM的详细介绍与之间的关系

    以下PHP CGI.Fastcgi.PHP-FPM的一些信息归纳和汇总----->详细介绍与之间的关系 一:CGI是干嘛的?CGI是为了保证web server传递过来的数据是标准格式的 web ...

  5. RabbitMQ消息队列(一): Detailed Introduction 详细介绍

     http://blog.csdn.net/anzhsoft/article/details/19563091 RabbitMQ消息队列(一): Detailed Introduction 详细介绍 ...

  6. doT.js详细介绍

    doT.js详细介绍   doT.js特点是快,小,无依赖其他插件. 官网:http://olado.github.iodoT.js详细使用介绍 使用方法:{{= }} for interpolati ...

  7. Linux截屏工具scrot用法详细介绍

    Scrot是Linux命令行中使用的截图工具,能够进行全屏.选取等操作,下面小编将针对Scrot截图工具的用法给大家做个详细介绍,通过操作实例来学习Scrot的使用.   在Linux中安装Scrot ...

  8. Oracle Merge into 详细介绍

    Oracle Merge into 详细介绍 /*Merge into 详细介绍MERGE语句是Oracle9i新增的语法,用来合并UPDATE和INSERT语句.通过MERGE语句,根据一张表或子查 ...

  9. cPage分页详细介绍

    asp.net中各种数据控件,datalist.gridview.Repeater等分页是最常用的功能,几乎任何一个B/S项目,无论是系统还是网站都会用到.分页时,读取整个数据,直接绑定到控件,都可以 ...

随机推荐

  1. BZOJ 1025: [SCOI2009]游戏( 背包dp )

    显然题目要求长度为n的置换中各个循环长度的lcm有多少种情况. 判断一个数m是否是满足题意的lcm. m = ∏ piai, 当∑piai ≤ n时是满足题意的. 最简单我们令循环长度分别为piai, ...

  2. 演练5-2:Contoso大学校园管理2

    一.添加列标题排序功能 我们将增加Student/Index页面的功能,为列标题添加超链接,用户可以点击列标题对那一列进行排序. 1.修改Index方法 public ActionResult Ind ...

  3. Cloud Engine

    Cloud Engine:大杀器如何炼成   郑昀 创建于2016/6/18 最后更新于2016/6/19 点击查看我的<如何从零搭建一个技术平台>,这是一个系列.转载时请注明“转载自旁观 ...

  4. Android NumberPicker和DatePicker分割线颜色设置

    NumberPicker /** * * 设置选择器的分割线颜色 * * @param numberPicker */ private void setDatePickerDividerColor(N ...

  5. ActivityGroup相关--getLocalActivityManager() 以及intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)用法

    ActivityGroup简介 1.ActivityGroup的核心就是继承了该类,能够通过getLocalActivityManager()得到一个LocalActivityManager 如,Lo ...

  6. Jquery学习笔记:删除节点的操作

    假设如下的html代码 <div id="mydiv" style="width:100px;height:100px;border:1px solid red&q ...

  7. 基于visual Studio2013解决C语言竞赛题之0703乾坤大挪移

       题目

  8. Creating Spatial Indexes(mysql 创建空间索引 The used table type doesn't support SPATIAL indexes)

    For MyISAM tables, MySQL can create spatial indexes using syntax similar to that for creating regula ...

  9. Regionals 2012, North America - Greater NY 解题报告

    这套题..除了几何的都出了 完全没时间学几何.杯具 A,B,J 水题不解释 C.Pen Counts 这题的话 写几个不等式限制边得范围就行了 然后枚举最小边 D.Maximum Random Wal ...

  10. python编写网络抓包分析脚本

    python编写网络抓包分析脚本 写网络抓包分析脚本,一个称手的sniffer工具是必不可少的,我习惯用Ethereal,简单,易用,基于winpcap的一个开源的软件 Ethereal自带许多协议的 ...