delphi控件安装与删除

附带通用控件安装方法:
———-
基本安装
1、对于单个控件,Componet–>install component..–>PAS或DCU文件–>install;
2、对于带*.dpk文件的控件包,File–>Open(下拉列表框中选*.dpk)–>install即可;
3、对于带*.bpl文件的控件包,Install Packages–>Add–>bpl文件名即可;
4、如果以上Install按钮为失效的话,试试Compile按钮;
5、是run time lib则在option下的packages下的runtimepackes加之。
如果编译时提示文件找不到的话,一般是控件的安装目录不在Delphi的Lib目录中,有两种方法可以解决:
1、反安装的源文件拷入到Delphi的Lib目录下;
2、或者Tools–>Environment Options中把控件源代码路径加入到Delphi的Lib目录中即可。
注意:所安装的控件是否与你所用的Delphi版本相适应。
———-
控件删除
在Component/Install Packages中删除。
选Component/configure Palette…
有pages和components两个区域
双击components区域,选中要删除得控件,下面有得Delete按钮
但系统提供的控件只能Hide,不能delete。
打开控件所在的包文件(*.dpk),从中删除控件那个文件,再重新编译该包即可。
如果是整个控件包都要删除的话,project->Option->Packages,删掉那个packages,收工。

标签: delphi 7

delphi TStringList 用法详解

[delphi]

//TStringList 常用方法与属性 :
var
List: TStringList;
i: Integer;
begin
List := TStringList.Create;
List.Add(‘Strings1’); {添加}
List.Add(‘Strings2′);
List.Exchange(0,1); {置换}
List.Insert(0,’Strings3’); {插入}
i := List.IndexOf(‘Strings1’); {第一次出现的位置}
List.Sort; {排序}
List.Sorted := True; {指定排序}
List.Count; {总数}
List.Text; {文本集合}
List.Delete(0); {删除, 0是第一个数据}
List.LoadfromFile(‘c:\tmp.txt’);{打开}
List.SaveToFile(‘c:\tmp.txt’); {保存}
List.Clear; {清空}
List.Free; {释放}
end;

//读入字符串
var
List: TStringList;
begin
List := TStringList.Create;
List.CommaText := ‘aaa,bbb,ccc,ddd’;
//相当于: List.Text := ‘aaa’ + #13#10 + ‘bbb’ + #13#10′ + ‘ccc’ + ‘#13#10’ + ‘ddd’;

ShowMessage(IntToStr(List.Count)); //4
ShowMessage(List[0]); //aaa

List.Free;
end;

//置换分隔符
var
List: TStringList;
begin
List := TStringList.Create;
List.Delimiter := ‘|’;
List.DelimitedText := ‘aaa|bbb|ccc|ddd’;

ShowMessage(IntToStr(List.Count)); //4
ShowMessage(List[0]); //aaa

List.Free;
end;

//类似的哈希表操作法
var
List: TStringList;
begin
List := TStringList.Create;

List.Add(‘aaa=111’);
List.Add(‘bbb=222’);
List.Add(‘ccc=333’);
List.Add(‘ddd=444’);

ShowMessage(List.Names[1]); //bbb
ShowMessage(List.ValuefromIndex[1]); //222
ShowMessage(List.Values[‘bbb’]); //222

//ValuefromIndex 可以赋值:
List.ValuefromIndex[1] := ‘2’;
ShowMessage(List[1]); //bbb=2

//可以通过 Values 赋值:
List.Values[‘bbb’] := ’22’;
ShowMessage(List[1]); //bbb=22

List.Free;
end;
//避免重复值
var
List: TStringList;
begin
List := TStringList.Create;

List.Add(‘aaa’);

List.Sorted := True; //需要先指定排序
List.Duplicates := dupIgnore; //如有重复值则放弃

List.Add(‘aaa’);

ShowMessage(List.Text); //aaa

//Duplicates 有3个可选值:
//dupIgnore: 放弃;
//dupAccept: 结束;
//dupError: 提示错误.

List.Free;
end;

//排序与倒排序
{排序函数}
function DescCompareStrings(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := -AnsiCompareText(List[Index1], List[Index2]);
end;

procedure TForm 1.Button1Click(Sender: TObject);
var
List: TStringList;
begin
List := TStringList.Create;

List.Add(‘bbb’);
List.Add(‘ccc’);
List.Add(‘aaa’);

//未排序
ShowMessage(List.Text); //bbb ccc aaa

//排序
List.Sort;
ShowMessage(List.Text); //aaa bbb ccc

//倒排序
List.CustomSort(DescCompareStrings); //调用排序函数
ShowMessage(List.Text); //ccc bbb aaa

//假如:
List.Sorted := True;
List.Add(‘999’);
List.Add(‘000’);
List.Add(‘zzz’);
ShowMessage(List.Text); //000 999 aaa bbb ccc zzz
end;

[/delphi]

Delphi通过解析搜狐网页来获取天气的函数

[delphi]

{
获取城市的天气
//使用方法
Edit1.text:=GetWeather(‘北京’);
}
[/delphi]
[delphi]
function GetWeather(City: String): String;
const
sys01='<table border=0 cellpadding=0 cellspacing=0 width=186 bgcolor=#ffffff>’;
sys02='<img src="’;
sys03=’" width=’;
sys04='<td class=blu01>’;
sys05='</td>’;
var
tmpstr,str1:string;
j:integer;
vFileStream:TFileStream;
http:tidhttp;
begin
http:=tidhttp.Create(nil);
tmpstr:=http.Get(‘http://weather.news.sohu.com/citymake.php?city=’+City);
j:=pos(sys01,tmpstr);
tmpstr:=copy(tmpstr,j,length(tmpstr));
j:=pos(sys02, tmpstr);
tmpstr:=copy(tmpstr,j+length(sys02),length(tmpstr));
j:=pos(sys03,tmpstr); //难道对字符串截取只能采用这种sb的方式么?
//pos不能从第几个字符开始查找么。擦
str1:=copy(tmpstr,0,j-1);

//下载图片
vFileStream:=TFileStream.Create(ExtractFilePath(application.ExeName)+’/weather.jpg’,fmCreate,fmShareDenyNone);
try
//IdHTTP1.Get(‘http://173.16.80.26/inputdb.mdb’,vFileStream);
HTTP.Get(str1,vFileStream);
//mage1.Picture.Bitmap.LoadFromStream(vfilestream);
finally
vFileStream.Free;
end;//try..finally
{sleep(1000);
image1.Picture.LoadFromFile( ExtractFilePath(application.ExeName)+’/weather.jpg’);
}
j:=pos(sys04,tmpstr);
tmpstr:=copy(tmpstr, j+length(sys04),length(tmpstr));
j:=pos(sys05,tmpstr);
str1:=copy(tmpstr,0,j-1);
str1:=stringreplace(str1,’ ‘,”,[rfreplaceall]);
str1:=stringreplace(str1,chr(13),”,[rfreplaceall]);
str1:=stringreplace(str1,chr(10),”,[rfreplaceall]);
str1:=stringreplace(str1,'<br>’,’ ‘,[rfreplaceall]);
http.Free;
result:=str1;
end;
[/delphi]

Delphi下字符编码WideString 还是 AnsiString

这里还有一个字符编码的问题。字符编码在Delphi7中已经得到了很大提高。
Delphi7自己的IDE虽然不能读取Unicode编码的源代码文件,但编译器已经支持
AnsiString和WideString的转换。也就是说,只要定义的时候定义WideString,
那么在后面直接给他赋值时,AnsiString自动转换为WideString,反之亦然。
这样有好处也有坏处,好处是在快速开发中,不需要考虑更多的字符转换问题,
能够比较平顺地从Win98向NT字符集转换,坏处是混淆了字符界限,深入看下
去,有时候搞不清我的内存里究竟是Ansi还是Wide,特别是希望仅仅使用宽字
符的情况下,更要留意字符格式的定义。

WideString保存为文本文件时,常用的有UTF-8、Unicode、Ansi、Unicode Big Endian,
其中 UTF-8 的格式,从文件读取的时候,需要利用 Delphi7 提供的 Utf8ToUnicode
转换一下全部编码,其他几种编码本身都不需要转换(BigEndian编码是摩托罗拉规范,是
intel 规范的 Unicode (即我们现在说的 WideString)编码的字符按字节反转,这符合摩
托罗拉生产的计算机芯片的构造特点,所以读取后要按 WORD 反转),但保存为相应格式的
文本文件时,必须按要求在文件头部写入一个编码识别记号,他们分别为:

Ansi:不需要
Unicode:$FEFF (十六进制编辑器看到的是高位在前显示$FFFE,以下同)
BigEndian:$FFFE (正好是上面 Unicode 的反转)
UTF-8:$BBEF $BF (三字节,十六进制编辑器里显示 $EFBB BF)

这样,其他编辑器读取时就可以识别出保存者把文本翻译成了什么编码。
Unicode(即WideString)只要写好文件头,后面的就按照保存Ansi文本一样把
文本写入文件,保存为Big Endian,则按WORD逐字节反转写入,保存为UTF-8
要利用UnicodeToUtf8转换后写入。

在XML解析中,如果带有非ASCII编码的文字,MS默认使用UTF-16编码,如果
原始文本是Ansi编码,这时将获得乱码的字符。这个编码不是Delphi造成的,是
MS的XML库所致,所以在使用非ASCII字符前,建议转换成UTF-8编码,上面例
子中我没有使用WideString,所以没有实现编码转换。

编码转换有很多现成的开源代码可以利用,其中影响最深远的就是JEDI的Unicoee.pas,
但这个文件很庞大,大约有250K大小,它还带有一个转换表的资源文件,如果
处理一些小型的字符转换就显得杀鸡用牛刀了。当然我们可以直接利用Delphi7
提供给我们的函数,比如:

function PUCS4Chars(const S: UCS4String): PUCS4Char;

function WideStringToUCS4String(const S: WideString): UCS4String;
function UCS4StringToWidestring(const S: UCS4String): WideString;

function UnicodeToUtf8(Dest: PChar; Source: PWideChar; MaxBytes: Integer): Integer;
function UnicodeToUtf8(Dest: PChar; MaxDestBytes: Cardinal; Source: PWideChar; SourceChars: Cardinal): Cardinal;

function Utf8ToUnicode(Dest: PWideChar; Source: PChar; MaxChars: Integer): Integer;
function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: Cardinal; Source: PChar; SourceBytes: Cardinal): Cardinal;

function Utf8Encode(const WS: WideString): UTF8String;
function Utf8Decode(const S: UTF8String): WideString;

function AnsiToUtf8(const S: string): UTF8string;
function Utf8ToAnsi(const S: UTF8string): string;

等等。这些已经足够使用了。轻量级的代码是OmniXML中的TGpTextStream,
不过这个代码有不少BUG,并且不支持BigEndian的写入(读取部分也因忘了使
用临时变量而错误)。这些都可以利用。

在Delphi7中,Edit等控件不支持WideString,但有一组TnTWare的开源控件可
以直接支持WideString。

所以,了解了这些内容后,就可以明确这么多编码在读入内存后变成了什么。
读入内存中的字符其实已经只剩下二种格式了:
要么是 AnsiString,
要么是WideString。
因此,对于认识字符编码的关键就是理解读取和理解保存,只有这二个地方需
要对编码有了解才能正确地完成工作。

哦,对了,还要补充一下Delphi中比较特殊的一个事情:本来我们全程使用了
WideString后,在NT系统下应该可以不考虑处于哪种语言环境的,但是Delphi
的全部控件都是基于Ansi的,因此,除非使用了象Tnt控件一样的显示控件,
否则都要注意字符集的定义。象Edit,如果要显示WideString,Edit的Line.Text
会自动转换为AnsiString,这个转换的依据是活动文档的键盘定义或者活动文档
的字符集定义(字符集定义优先),因此一定不要忘记把Edit字符集设置为与
文本相适应的标志,比如中文,就设置为GB2313_CHARSET,这样,转换时会
使用936的中文字符集。这个设置与具体使用的字体无关,只要强制把这个属
性设置好了,字体是否支持这个集合由系统自动转换。

如果要了解更多这方面的情况,建议使用虚拟电脑模拟语言环境来观察。暂时就先到这里。

Delphi Stream对象 详解

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部件。

Delphi 判断文本文件的编码格式并读取内容

这里指的文本是用于Windows系统中的扩展名为.txt的文件。

Notepad(记事本)只支持四种格式:ANSI/Unicode/Unicode big endian/UFT-8,在Delphi中如何判断与读取这些不同格式的文本呢?

首先,不同编码的文本,是根据文本的前两个字节来定义其编码格式的。定义如下:

ANSI: 无格式定义;
Unicode: 前两个字节为FFFE;
Unicode big endian: 前两字节为FEFF;
UTF-8: 前两字节为EFBB;

知道了各种编码格式的区别,写代码就容易了,以下是我在一个软件中写的处理代码:
(注意,Delphi的TMemo/TRichEdit只支持ANSI的文本文件,其它编码格式的文件需要
自行写代码转换成GB2312或BIG5,方能正确显示)

标签: <无>

代码片段(1)

[代码]

[Delphi/Pascal]代码
[delphi]
type
TTextFormat=(tfAnsi,tfUnicode,tfUnicodeBigEndian,tfUtf8);
const
TextFormatFlag:array[tfAnsi..tfUtf8] of word=($0000,$FFFE,$FEFF,$EFBB);

function WordLoHiExchange(w:Word):Word;register;
asm
XCHG AL, AH
end;

{ TextFormat返回文本编码类型,sText未经处理的文本 }
procedure ReadTextFile(const FileName: string;
var TextFormat: TTextFormat; var sText:string);
var
w:Word;
b:Byte;
begin
with TFileStream.Create(FileName,fmOpenRead or fmShareDenyNone) do
try
Read(w,2);
w:=WordLoHiExchange(w);//因为是以Word数据类型读取,故高低字节互换
if w = TextFormatFlag[tfUnicode] then
TextFormat:= tfUnicode
else if w = TextFormatFlag[tfUnicodeBigEndian] then
TextFormat:= tfUnicodeBigEndian
else if w = TextFormatFlag[tfUtf8] then
begin
Read(b,1);//这里要注意一下,UFT-8必须要跳过三个字节。
TextFormat:=tfUtf8;
end else
begin
TextFormat:=tfANSI;
Position:=0;
end;
SetLength(sText,Size-Position);
ReadBuffer(sText[1],Size-Position);
finally
Free;
end;
end;
[/delphi]