﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-没话说了-随笔分类-Delphi</title><link>http://www.blogjava.net/howard/category/2164.html</link><description>所学甚浅，所知甚少</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 01:06:18 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 01:06:18 GMT</pubDate><ttl>60</ttl><item><title>在Dephi中使用TStream读写数据的技巧</title><link>http://www.blogjava.net/howard/archive/2005/07/15/7798.html</link><dc:creator>howard</dc:creator><author>howard</author><pubDate>Fri, 15 Jul 2005 12:41:00 GMT</pubDate><guid>http://www.blogjava.net/howard/archive/2005/07/15/7798.html</guid><wfw:comment>http://www.blogjava.net/howard/comments/7798.html</wfw:comment><comments>http://www.blogjava.net/howard/archive/2005/07/15/7798.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/howard/comments/commentRss/7798.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/howard/services/trackbacks/7798.html</trackback:ping><description><![CDATA[From: <A href="http://xuguohua.diy.myrice.com/skill/34.htm">http://xuguohua.diy.myrice.com/skill/34.htm</A>&nbsp;<BR>&nbsp;&nbsp;&nbsp; 在Dephi中提供了一个抽象的数据类型TStream来支持对流式数据的操作。这些数据通常来自文件、数据库、内存对象、OLE对象等，TStream提供了统一、简洁的方法来进行数据的读写。在通常情况下，我们并不需要直接使用TStream类，对流式数据的读写封装在VCL控件的方法中。但是如果这些方法无法满足我们的要求，就需要自己手动控制数据的读写。 
<H3><FONT color=#a30004>一、 TStream的常用的方法和属性：</FONT></H3><FONT color=#ffffff>----</FONT> 1. function Read(var Buffer; Count: Longint): Longint; virtual; abstract 
<P><FONT color=#ffffff>----</FONT> 2. function Write(const Buffer; Count: Longint): Longint; virtual; abstract; 
<P><FONT color=#ffffff>----</FONT> 3. function Seek(Offset: Longint; Origin: Word): Longint; virtual; abstract; 
<P><FONT color=#ffffff>----</FONT> 4. property Position: Longint; 
<P><FONT color=#ffffff>----</FONT> 5. property Size: Longint 
<P><FONT color=#ffffff>----</FONT> Read，Write，Seek都是纯虚函数，提供了数据读写和定位的抽象的方法。Read方法将数据从Stream中读到Buffer缓冲区中，Write则实现相反的操作，返回值表示实际读写数据的大小。Seek提供了在Stream中移动数据指针的方法。参数Origin可以取soFromBeginning，soFromCurrent，soFromEnd 三个值，Offset是偏移量，返回值是当前Stream数据指针的位置。 
<P><FONT color=#ffffff>----</FONT> Position表示了数据指针在Stream中的位置。这个属性是可读写的，它实际上就是通过调用Seek方法实现的，所以实际使用时使用这个属性更为方便一些。Size属性表示当前Stream的大小，对于不同的Stream，有些时候是只读的。 
<H3><FONT color=#a30004>二、 Stream数据的读写。</FONT></H3><FONT color=#ffffff>----</FONT> 1. SaveToStream(Stream: TStream ); //将类中的数据写到Stream的当前位置中 
<P><FONT color=#ffffff>----</FONT> 2. LoadFromStream(Stream: TStream); //从当前位置读入Stream里的数据 
<P><FONT color=#ffffff>----</FONT> 实际使用时我们基本上只要使用上面两个函数就可以了。 
<H3><FONT color=#a30004>三、 例子</FONT></H3><FONT color=#ffffff>----</FONT> TStream的继承树图如图1所示(略)，实际使用时比较常用的是TFileStream，TMemoryStream，TblobStream，就以这三种流举一例说明具体用法。 
<P><FONT color=#ffffff>----</FONT> 创建一个窗体Form1，放置三个按钮btnRead，btnInvert，btnSave和一个文件打开对话框OpenDialog1以及数据控件DataSource1，Table1，test. 
<P><FONT color=#ffffff>----</FONT> 使用Dephi提供的Database Desktop创建一个表test，表里有一个字段域Image，数据库文件名存为test.db。在窗体上放置一个TDatabase控件dbTest，一个TTable控件Table1,一个DataSource控件DataSource1,一个TDBNavigator控件DBNavigator1。将dbTest与刚才Desktop创建的数据库相连，Table1的TableName属性设为test.db，DataSource1的DataSet属性设为Table1，DBNavigator1的DataSource属性设为DataSource1，VisibleButtons属性前四个设为TRUE。此外，将dbtest的Connected设为TRUE，Table1的Active属性设为TRUE，使得数据库一开始就处于打开状态。 
<P><FONT color=#ffffff>----</FONT> 事件代码编写如下： 
<P><FONT color=#ffffff>----</FONT> 1. btnRead的Click事件，这里演示了TFileStream的用法。 <PRE><FONT size=2>var
  MS: TFileStream;
begin
  if OpenDialog1.Execute then
  begin
MS:=TFileStream.Create
(OpenDialog1.FileName, fmOpenRead);
    Image1.Picture.Bitmap.LoadFromStream(MS);
    MS.Free;
  end;
end;</FONT>
</PRE><FONT color=#ffffff>----</FONT> 2. btnInvert的Click事件，这里演示了TMemoryStream的用法。其中使用了Invert函数，这是一个简单的将图象反色的函数（仅对真彩图象有效），它返回一个指向处理过的图象数据块的指针。 <PRE><FONT size=2>var
  M
S: TMemoryStream;
  pImage: pointer;
begin
  MS:=TMemoryStream.create;
  Image1.Picture.Bitmap.SaveToStream(MS);
  MS.Position:=0;
  pImage:=Invert(MS.Memory, MS.size); 
 //Memory属性是指向实际内存块的指针
  MS.Write(pImage^,MS.size);
  MS.Position:=0;         
 //上一行代码使指针移到了Stream末尾，所以要复位
  Image1.Picture.Bitmap.LoadFromStream(MS);
  FreeMem(pImage);			
  MS.Free;
end;</FONT>

<FONT size=2> Invert函数如下：
function TForm1.Invert
(pImage: pointer; size: Integer): pointer;
var
  pData, pMem: PChar;
  i: Integer;
begin
  pMem:=AllocMem(size);
  CopyMemory(pMem,pImage,size);
  pData:=pMem+54;
  for i:=0 to size-54-1 do
  begin
    pData^:=Char(not integer(pData^));
    pData:=pData+1;
  end;
  Result:=pMem;
end;</FONT>
</PRE><FONT color=#ffffff>----</FONT> 1. btnSave的Click事件，这里演示了TMemoryStream的另一种用法，将Stream中的数据写到数据库中去。 <PRE><FONT size=2>var
  MS: TMemoryStream;
begin
  MS:=TMemoryStream.create;
  Image1.Picture.Bitmap.SaveToStream(MS);
  MS.Position:=0;
  Table1.Append;   
 //在数据库中添加一条记录
  TBlobField(Table1.FieldbyName
('image')).LoadFromStream(MS);
  Table1.Post;	      
//将所作的更新写入数据库
end;</FONT>
</PRE><FONT color=#ffffff>----</FONT> 4. DBNavigator1的Click事件，这里演示了TBlobStream的用法，使用了和写入时不同的方法来读出数据库的图象数据。 <PRE><FONT size=2>var
  MS: TStream;
begin
  with Table1 do
  MS:=CreateBlobStream
(FieldbyName('image'),bmRead);
  Image1.Picture.Bitmap.
LoadFromStream(MS);
  MS.Free;
end;</FONT>
</PRE><FONT color=#ffffff>----</FONT> 现在你已经能够在文件，数据库，内存中任意读写数据流了。试试看吧！<img src ="http://www.blogjava.net/howard/aggbug/7798.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/howard/" target="_blank">howard</a> 2005-07-15 20:41 <a href="http://www.blogjava.net/howard/archive/2005/07/15/7798.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>