请指点一下TMemoryStream之类的流类的几个特征方法的使用(50分)

  • 主题发起人 主题发起人 Beyondbill
  • 开始时间 开始时间
B

Beyondbill

Unregistered / Unconfirmed
GUEST, unregistred user!
如题,我在自己的程序中需要用到TMemoryStream之类的流类,可是怎么用都不是很灵活,请大家指点一下
具体指点方法有Write, WriteBuffer, Read, ReadBuffer
示例请按照我写的做
1. 分别用Write, WriteBuffer向流中写入"hello,test"
2. 分别用Read, ReadBuffer从流中读取出"hello,test"
 
procedure WriteString(Value : TStream
AStr : String);
var ii : Integer;
begin
WriteInteger(Value,Length(AStr));
for ii := 1 to Length(AStr) do
Value.Write(AStr[ii],1);
end;

function ReadString(Value : TStream) : String;
var ii,ACount : Integer;
AStr : string;
begin
ACount := ReadInteger(Value);
SetLength(AStr,ACount);
for ii := 1 to ACount do
Value.Read(AStr[ii],1);
Result := AStr;
end;
 
问题: 请教MemoryStream的使用方法 ( 积分: 50 )
分类: Object Pascal

来自: ranjiao, 时间: 2005-08-15 18:45:00, ID: 3167898
我想用MemoryStream反复读取文件操作,但是我调用clear和free想清除内存的时候都会报错。。。
应该怎么弄?

来自: chenybin, 时间: 2005-08-15 20:24:58, ID: 3167929
先看看你的代码

http://www.delphibbs.com/delphibbs/modifyl.asp?lid=1474545

谈Delphi编程中“流”的应用

陈经韬


什么是流?流,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的,而不用关心流的另一头数据的真正流向。流不但可以处理文件,还可以处理动态内存、网络数据等多种数据形式。如果你对流的操作非常熟练,在程序中利用流的方便性,写起程序会大大提高效率的。
下面,笔者通过四个实例:EXE文件加密器、电子贺卡、自制OICQ和网络屏幕传输来说明Delphi编程中“流”的利用。这些例子中的一些技巧曾经是很多软件的秘密而不公开的,现在大家可以无偿的直接引用其中的代码了。
“万丈高楼平地起”,在分析实例之前,我们先来了解一下流的基本概念和函数,只有在理解了这些基本的东西后我们才能进行下一步。请务必认真领会这些基本方法。当然,如果你对它们已经很熟悉了,则可以跳过这一步。

一、Delphi中流的基本概念及函数声明
在Delphi中,所有流对象的基类为TStream类,其中定义了所有流的共同属性和方法。
TStream类中定义的属性介绍如下:
1、Size:此属性以字节返回流中数据大小。
2、Position:此属性控制流中存取指针的位置。
Tstream中定义的虚方法有四个:
1、Read:此方法实现将数据从流中读出。函数原形为:
Function Read(var Buffer;Count:Longint):Longint;virtual;abstract

参数Buffer为数据读出时放置的缓冲区,Count为需要读出的数据的字节数,该方法返回值为实际读出的字节数,它可以小于或等于Count中指定的值。
2、Write:此方法实现将数据写入流中。函数原形为:
Function Write(var Buffer;Count:Longint):Longint;virtual;abstract

参数Buffer为将要写入流中的数据的缓冲区,Count为数据的长度字节数,该方法返回值为实际写入流中的字节数。
3、Seek:此方法实现流中读取指针的移动。函数原形为:
Function Seek(Offset:Longint;Origint:Word):Longint;virtual;abstract

参数Offset为偏移字节数,参数Origint指出Offset的实际意义,其可能的取值如下:
soFromBeginning:Offset为移动后指针距离数据开始的位置。此时Offset必须大于或者等于零。
soFromCurrent:Offset为移动后指针与当前指针的相对位置。
soFromEnd:Offset为移动后指针距离数据结束的位置。此时Offset必须小于或者等于零。该方法返回值为移动后指针的位置。
4、Setsize:此方法实现改变数据的大小。函数原形为:
Function Setsize(NewSize:Longint);virtual

另外,TStream类中还定义了几个静态方法:
1、ReadBuffer:此方法的作用是从流中当前位置读取数据。函数原形为:
Procedure ReadBuffer(var Buffer;Count:Longint)

参数的定义跟上面的Read相同。注意:当读取的数据字节数与需要读取的字节数不相同时,将产生EReadError异常。
2、WriteBuffer:此方法的作用是在当前位置向流写入数据。函数原形为:
Procedure WriteBuffer(var Buffer;Count:Longint)

参数的定义跟上面的Write相同。注意:当写入的数据字节数与需要写入的字节数不相同时,将产生EWriteError异常。
3、CopyFrom:此方法的作用是从其它流中拷贝数据流。函数原形为:
Function CopyFrom(Source:TStream;Count:Longint):Longint

参数Source为提供数据的流,Count为拷贝的数据字节数。当Count大于0时,CopyFrom从Source参数的当前位置拷贝Count个字节的数据;当Count等于0时,CopyFrom设置Source参数的Position属性为0,然后拷贝Source的所有数据;
TStream还有其它派生类,其中最常用的是TFileStream类。使用TFileStream类来存取文件,首先要建立一个实例。声明如下:
constructor Create(const Filename:string;Mode:Word)

Filename为文件名(包括路径),参数Mode为打开文件的方式,它包括文件的打开模式和共享模式,其可能的取值和意义如下:

打开模式:
fmCreate :用指定的文件名建立文件,如果文件已经存在则打开它。
fmOpenRead :以只读方式打开指定文件
fmOpenWrite :以只写方式打开指定文件
fmOpenReadWrite:以写写方式打开指定文件
共享模式:
fmShareCompat :共享模式与FCBs兼容
fmShareExclusive:不允许别的程序以任何方式打开该文件
fmShareDenyWrite:不允许别的程序以写方式打开该文件
fmShareDenyRead :不允许别的程序以读方式打开该文件
fmShareDenyNone :别的程序可以以任何方式打开该文件

TStream还有一个派生类TMemoryStream,实际应用中用的次数也非常频繁。它叫内存流,就是说在内存中建立一个流对象。它的基本方法和函数跟上面是一样的。
好了,有了上面的基础后,我们就可以开始我们的编程之行了。
-----------------------------------------------------------------------
二、实际应用之一:利用流制作EXE文件加密器、捆绑、自解压文件及安装程序

我们先来说一下如何制作一个EXE文件加密器吧。
EXE文件加密器的原理:建立两个文件,一个用来添加资源到另外一个EXE文件里面,称为添加程序。另外一个被添加的EXE文件称为头文件。该程序的功能是把添加到自己里面的文件读出来。Windows下的EXE文件结构比较复杂,有的程序还有校验和,当发现自己被改变后会认为自己被病毒感染而拒绝执行。所以我们把文件添加到自己的程序里面,这样就不会改变原来的文件结构了。我们先写一个添加函数,该函数的功能是把一个文件当作一个流添加到另外一个文件的尾部。函数如下:

Function Cjt_AddtoFile(SourceFile,TargetFile:string):Boolean

var
Target,Source:TFileStream

MyFileSize:integer

begin
try
Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareExclusive)

Target:=TFileStream.Create(TargetFile,fmOpenWrite or fmShareExclusive)

try
Target.Seek(0,soFromEnd);//往尾部添加资源
Target.CopyFrom(Source,0)

MyFileSize:=Source.Size+Sizeof(MyFileSize);//计算资源大小,并写入辅程尾部
Target.WriteBuffer(MyFileSize,sizeof(MyFileSize))

finally
Target.Free

Source.Free

end

except
Result:=False

Exit

end

Result:=True

end

有了上面的基础,我们应该很容易看得懂这个函数。其中参数SourceFile是要添加的文件,参数TargetFile是被添加到的目标文件。比如说把a.exe添加到b.exe里面可以:Cjt_AddtoFile('a.exe',b.exe');如果添加成功就返回True否则返回假。
根据上面的函数我们可以写出相反的读出函数:
Function Cjt_LoadFromFile(SourceFile,TargetFile :string):Boolean

var
Source:TFileStream

Target:TMemoryStream

MyFileSize:integer

begin
try
Target:=TMemoryStream.Create

Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareDenyNone)

try
Source.Seek(-sizeof(MyFileSize),soFromEnd)

Source.ReadBuffer(MyFileSize,sizeof(MyFileSize));//读出资源大小
Source.Seek(-MyFileSize,soFromEnd);//定位到资源位置
Target.CopyFrom(Source,MyFileSize-sizeof(MyFileSize));//取出资源
Target.SaveToFile(TargetFile);//存放到文件
finally
Target.Free

Source.Free

end

except
Result:=false

Exit

end

Result:=true

end

其中参数SourceFile是已经添加了文件的文件名称,参数TargetFile是取出文件后保存的目标文件名。比如说Cjt_LoadFromFile('b.exe','a.txt');在b.exe中取出文件保存为a.txt。如果取出成功就返回True否则返回假。
打开Delphi,新建一个工程,在窗口上放上一个Edit控件Edit1和两个Button:Button1和Button2。Button的Caption属性分别设置为“确定”和“取消”。在Button1的Click事件中写代码:
var S:string

begin
S:=ChangeFileExt(Application.ExeName,'.Cjt')

if Edit1.Text='790617' then
begin
Cjt_LoadFromFile(Application.ExeName,S)

{取出文件保存在当前路径下并命名"原文件.Cjt"}
Winexec(pchar(S),SW_Show);{运行"原文件.Cjt"}
Application.Terminate;{退出程序}
end
else
Application.MessageBox('密码不对,请重新输入!','密码错误',MB_ICONERROR+MB_OK)

编译这个程序,并把EXE文件改名为head.exe。新建一个文本文件head.rc,内容为: head exefile head.exe,然后把它们拷贝到Delphi的BIN目录下,执行Dos命令Brcc32.exe head.rc,将产生一个head.res的文件,这个文件就是我们要的资源文件,先留着。
我们的头文件已经建立了,下面我们来建立添加程序。
新建一个工程,放上以下控件:一个Edit,一个Opendialog,两个Button1的Caption属性分别设置为"选择文件"和"加密"。在源程序中添加一句:{$R head.res}并把head.res文件拷贝到程序当前目录下。这样一来就把刚才的head.exe跟程序一起编译了。
在Button1的Cilck事件里面写下代码:
if OpenDialog1.Execute then Edit1.Text:=OpenDialog1.FileName

在Button2的Cilck事件里面写下代码:
var S:String

begin
S:=ExtractFilePath(Edit1.Text)

if ExtractRes('exefile','head',S+'head.exe') then
if Cjt_AddtoFile(Edit1.Text,S+'head.exe') then
if DeleteFile(Edit1.Text) then
if RenameFile(S+'head.exe',Edit1.Text) then
Application.MessageBox('文件加密成功!','信息',MB_ICONINFORMATION+MB_OK)
else
begin
if FileExists(S+'head.exe') then DeleteFile(S+'head.exe')

Application.MessageBox('文件加密失败!','信息',MB_ICONINFORMATION+MB_OK)
end

end

其中ExtractRes为自定义函数,它的作用是把head.exe从资源文件中取出来。
Function ExtractRes(ResType, ResName, ResNewName : String):boolean

var
Res : TResourceStream

begin
try
Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType))

try
Res.SavetoFile(ResNewName)

Result:=true

finally
Res.Free

end

except
Result:=false

end

end

注意:我们上面的函数只不过是简单的把一个文件添加到另一个文件的尾部。实际应用中可以改成可以添加多个文件,只要根据实际大小和个数定义好偏移地址就可以了。比如说文件捆绑机就是把两个或者多个程序添加到一个头文件里面。那些自解压程序和安装程序的原理也是一样的,不过多了压缩而已。比如说我们可以引用一个LAH单元,把流压缩后再添加,这样文件就会变的很小。读出来时先解压就可以了。另外,文中EXE加密器的例子还有很多不完善的地方,比如说密码固定为"790617",取出EXE运行后应该等它运行完毕后删除等等,读者可以自行修改。

---------------------------------------------------------------------
三、实际应用之二:利用流制作可执行电子贺卡

我们经常看到一些电子贺卡之类的制作软件,可以让你自己选择图片,然后它会生成一个EXE可执行文件给你。打开贺卡时就会一边放音乐一边显示出图片来。现在学了流操作之后,我们也可以做一个了。
添加图片过程我们可以直接用前面的Cjt_AddtoFile,而现在要做的是如何把图像读出并显示。我们用前面的Cjt_LoadFromFile先把图片读出来保存为文件再调入也是可以的,但是还有更简单的方法,就是直接把文件流读出来显示,有了流这个利器,一切都变的简单了。
现在的图片比较流行的是BMP格式和JPG格式。我们现在就针对这两种图片写出读取并显示函数。

Function Cjt_BmpLoad(ImgBmp:TImage;SourceFile:String):Boolean

var
Source:TFileStream

MyFileSize:integer

begin
Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareDenyNone)

try
try
Source.Seek(-sizeof(MyFileSize),soFromEnd)

Source.ReadBuffer(MyFileSize,sizeof(MyFileSize));//读出资源
Source.Seek(-MyFileSize,soFromEnd);//定位到资源开始位置
ImgBmp.Picture.Bitmap.LoadFromStream(Source)

finally
Source.Free

end

except
Result:=False

Exit

end

Result:=True

end

上面是读出BMP图片的,下面的是读出JPG图片的函数,因为要用到JPG单元,所以要在程序中添加一句:uses jpeg。

Function Cjt_JpgLoad(JpgImg:Timage;SourceFile:String):Boolean

var
Source:TFileStream

MyFileSize:integer

Myjpg: TJpegImage

begin
try
Myjpg:= TJpegImage.Create

Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareDenyNone)

try
Source.Seek(-sizeof(MyFileSize),soFromEnd)

Source.ReadBuffer(MyFileSize,sizeof(MyFileSize))

Source.Seek(-MyFileSize,soFromEnd)

Myjpg.LoadFromStream(Source)

JpgImg.Picture.Bitmap.Assign(Myjpg)

finally
Source.Free

Myjpg.free

end

except
Result:=false

Exit

end

Result:=true

end

有了这两个函数,我们就可以制作读出程序了。下面我们以BMP图片为例:
运行Delphi,新建一个工程,放上一个显示图像控件Image1。在窗口的Create事件中写上一句就可以了:
Cjt_BmpLoad(Image1,Application.ExeName)

这个就是头文件了,然后我们用前面的方法生成一个head.res资源文件。
下面就可以开始制作我们的添加程序了。全部代码如下:
unit Unit1


interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, ExtDlgs


type
TForm1 = class(TForm)
Edit1: TEdit

Button1: TButton

Button2: TButton

OpenPictureDialog1: TOpenPictureDialog

procedure FormCreate(Sender: TObject)

procedure Button1Click(Sender: TObject)

procedure Button2Click(Sender: TObject)

private
Function ExtractRes(ResType, ResName, ResNewName : String):boolean

Function Cjt_AddtoFile(SourceFile,TargetFile:string):Boolean

{ Private declarations }
public
{ Public declarations }
end


var
Form1: TForm1


implementation

{$R *.DFM}
Function TForm1.ExtractRes(ResType, ResName, ResNewName : String):boolean

var
Res : TResourceStream

begin
try
Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType))

try
Res.SavetoFile(ResNewName)

Result:=true

finally
Res.Free

end

except
Result:=false

end

end

Function TForm1.Cjt_AddtoFile(SourceFile,TargetFile:string):Boolean

var
Target,Source:TFileStream

MyFileSize:integer

begin
try
Source:=TFileStream.Create(SourceFile,fmOpenRead or fmShareExclusive)

Target:=TFileStream.Create(TargetFile,fmOpenWrite or fmShareExclusive)

try
Target.Seek(0,soFromEnd);//往尾部添加资源
Target.CopyFrom(Source,0)

MyFileSize:=Source.Size+Sizeof(MyFileSize);//计算资源大小,并写入辅程尾部
Target.WriteBuffer(MyFileSize,sizeof(MyFileSize))

finally
Target.Free

Source.Free

end

except
Result:=False

Exit

end

Result:=True

end

procedure TForm1.FormCreate(Sender: TObject)

begin
Caption:='Bmp2Exe演示程序.作者:陈经韬'

Edit1.Text:=''

OpenPictureDialog1.DefaultExt := GraphicExtension(TBitmap)

OpenPictureDialog1.Filter := GraphicFilter(TBitmap)


Button1.Caption:='选择BMP图片'

Button2.Caption:='生成EXE'

end


procedure TForm1.Button1Click(Sender: TObject)

begin
if OpenPictureDialog1.Execute then
Edit1.Text:=OpenPictureDialog1.FileName

end


procedure TForm1.Button2Click(Sender: TObject)

var
HeadTemp:String

begin
if Not FileExists(Edit1.Text) then
begin
Application.MessageBox('BMP图片文件不存在,请重新选择!','信息',MB_ICONINFORMATION+MB_OK)
Exit

end

HeadTemp:=ChangeFileExt(Edit1.Text,'.exe')

if ExtractRes('exefile','head',HeadTemp) then
if Cjt_AddtoFile(Edit1.Text,HeadTemp) then
Application.MessageBox('EXE文件生成成功!','信息',MB_ICONINFORMATION+MB_OK)
else
begin
if FileExists(HeadTemp) then DeleteFile(HeadTemp)

Application.MessageBox('EXE文件生成失败!','信息',MB_ICONINFORMATION+MB_OK)
end

end

end.
怎么样?很神奇吧:)把程序界面弄的漂亮点,再添加一些功能,你会发现比起那些要注册的软件来也不会逊多少吧。

来自: ranjiao, 时间: 2005-08-15 19:41:40, ID: 3167931
free一调用就会出错

来自: chenybin, 时间: 2005-08-15 20:24:37, ID: 3167954
把你的代码贴出来看看

来自: ranjiao, 时间: 2005-08-15 21:03:52, ID: 3168004
begin//download <<===BUG!!!
MemoryStream.Position:=0

loadfile(list.data[0],MemoryStream,msize)

memo1.Lines.add('file loaded.')

socket.SendText(inttostr(msize))

end

我在远程控制,其中涉及到的就是这几行代码了,下面是整个代码,有点多
unit server


interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, StdCtrls, ExtCtrls, Jpeg, unitserver


type
TServerForm = class(TForm)
ServerSocket1: TServerSocket

BtnListen: TButton

Memo1: TMemo

BtnExit: TButton

EdtSend: TEdit

BtnSend: TButton

Timer1: TTimer

CbControl: TCheckBox

Image: TImage

BtnClear: TButton

procedure BtnClearClick(Sender: TObject)

procedure Button1Click(Sender: TObject)

procedure EdtSendKeyPress(Sender: TObject
var Key: Char)

procedure ServerSocket1ClientError(Sender: TObject

Socket: TCustomWinSocket
ErrorEvent: TErrorEvent

var ErrorCode: Integer)

procedure CbControlClick(Sender: TObject)

procedure ServerSocket1ClientDisconnect(Sender: TObject

Socket: TCustomWinSocket)

procedure Timer1Timer(Sender: TObject)

procedure FormCreate(Sender: TObject)

procedure ServerSocket1ClientRead(Sender: TObject

Socket: TCustomWinSocket)

procedure BtnSendClick(Sender: TObject)

procedure ServerSocket1Accept(Sender: TObject
Socket: TCustomWinSocket)

procedure BtnListenClick(Sender: TObject)

procedure BtnExitClick(Sender: TObject)

private
{ Private declarations }
public
{ Public declarations }
end


var
ServerForm: TServerForm

control,shaking:boolean

memoryStream:TMemoryStream

size:longint

Receiving:integer

filepath:string

implementation

{$R *.dfm}

procedure capture

var
BitMap:TBitMap

jpg:TJpegImage

desk:TCanvas


begin
bitmap:=tbitmap.Create

jpg:=tjpegimage.Create

desk:=tcanvas.Create
//以下代码为取得当前屏幕图象
desk.Handle:=getdc(hwnd_desktop)

MemoryStream:=tmemorystream.Create
//初始化流m1,在用sendstream(m1)发送流后,
with bitmap do
begin
width:=screen.Width

height:=screen.Height

jpg.CompressionQuality:=50
{压缩质量}
jpg.Compress

canvas.CopyRect(canvas.cliprect,desk,desk.cliprect)

end

jpg.Assign(bitmap)
//将图象转成JPG格式
jpg.SaveToStream(MemoryStream)
//将JPG图象写入流中
jpg.free

MemoryStream.Position:=0

end


procedure TServerForm.BtnExitClick(Sender: TObject)

begin
close

end


procedure TServerForm.BtnListenClick(Sender: TObject)

begin
ServerSocket1.active:=NOT ServerSocket1.active

if not ServerSocket1.Active then
begin
BtnListen.Caption:='Listen'

memo1.Lines.add('Listen ended.')

end
else
begin
BtnListen.Caption:='End Listen'

memo1.Lines.add('Listening...')

end

end


procedure TServerForm.ServerSocket1Accept(Sender: TObject
Socket: TCustomWinSocket)

begin
memo1.Lines.Add('Client from '+ServerSocket1.Socket.Connections[0].RemoteAddress+' connected.')

end


procedure TServerForm.BtnSendClick(Sender: TObject)

begin
if not ServerSocket1.Socket.Connected then exit

ServerSocket1.Socket.Connections[0].SendText(EdtSend.Text)

memo1.Lines.add('Server :'+EdtSend.text)

end




procedure TServerForm.ServerSocket1ClientRead(Sender: TObject

Socket: TCustomWinSocket)

var
msize,iscmd:integer

cmd,temp:string


//delcaration of cmdlist
// maxcount=10

// CMDList:array[0..maxcount-1] of string=
// ('#CLogOff',
// '#CPowerOff',
// '#CReboot',
// '#CShakeMouse',
// '#CCapture',
// '#CSendStream',
// '#CListDrive',
// '#CListFile',
// '#CDownload',
// '#CUpload',
// '#CExit')


procedure ReceiveStream

var
len:integer

buffer:array [0..10000] of byte

begin
if size=0 then
begin
size:=strtoint(Socket.ReceiveText)

Socket.SendText('#CSendStream')
//ask client to send the stream
end
else
begin
len:=socket.ReceiveLength
//读出包长度
socket.ReceiveBuf(buffer,len)
//接收数据包并读入缓冲区内
memorystream.Write(buffer,len)
//追加入流M中
end

end


begin
if Receiving<>0 then
// Receiving is the Flag of what socket is going to receive
// 1:Stream of file that client is iploading
case Receiving of
1:begin//receive stream
ReceiveStream

if MemoryStream.Size>=size then
begin
MemoryStream.SaveToFile(list.data[0])

Receiving:=0

end

end

end
else
begin
temp:=Socket.ReceiveText

memo1.Lines.Add('Client: '+temp)

iscmd:=DealWithCMD(temp)

//check if the message recevied is a command
//and save the var in list.
if iscmd<>0 then
begin
if control then
begin
case iscmd of
1:begin//log off //<<=====DEBUGED======>>
ExitWindowsEx(EWX_Logoff,0)

end

2:begin//Power Off //<<=====DEBUGED======>>
ExitWindowsEx(EWX_PowerOff,0)

end

3:begin//Reboot //<<=====DEBUGED======>>
ExitWindowsEx(EWX_Reboot,0)

end

4:begin//Shake Mouse //<<=====DEBUGED======>>
shaking:=not shaking

Timer1.Enabled:=true

if shaking then
memo1.Lines.Add('Your mouse is going mad.')
else
memo1.Lines.Add('What''s wrong with your mouse?')

end

5:begin//Capture the Screen<<=====DEBUGED======>>
capture
//capture the screen and compress it into jpeg
//and then save it to MemoryStream
cmd:=inttostr(MemoryStream.Size)

socket.SendText(cmd)

end

6:begin//Transport the Stream<<=====DEBUGED======>>
MemoryStream.Position:=0

socket.SendStream(MemoryStream)

end

7:begin//List the drives.<<=====DEBUGED======>>
ListDrive(cmd)

socket.SendText(cmd)

end

8:begin//List the files and dirs<<=====DEBUGED======>>
listFile(list.data[0],'*.*',cmd)

socket.SendText(cmd)

init

end

9:begin//download <<===BUG!!!
MemoryStream.Position:=0

loadfile(list.data[0],MemoryStream,msize)

memo1.Lines.add('file loaded.')

socket.SendText(inttostr(msize))

end

10:begin //upload
// filepath:=list.data[0]

// socket.SendText('#CSendStream')

// receiving:=1

end

11:begin
Application.Terminate

end

12:begin
ServerForm.Show

end

end;//case
end //eof if control
else
socket.SendText('#Server is not controlable.')

end//eof if iscmd }
else
begin
// memo1.Lines.Add('Client: '+temp)

end

end;//eof else receiving
end


procedure TServerForm.FormCreate(Sender: TObject)

begin
BtnListen.Click

shaking:=false

control:=true

MemoryStream:=TMemoryStream.Create

Receiving:=0

size:=0

init;//procedure in unit1

end


procedure TServerForm.Timer1Timer(Sender: TObject)

const //This procedure change the pos of mouse
maxn=100
//and it make mouse like shaking...
var
pos:TPoint

// x,y:integer

begin
if shaking then
begin
GetCursorPos(pos)

randomize

pos.X:=pos.X+random(maxn)-(maxn div 2)

pos.Y:=pos.y+random(maxn)-(maxn div 2)

SetCursorPos(pos.x,pos.y)

end
else
Timer1.enabled:=false

end


procedure TServerForm.ServerSocket1ClientDisconnect(Sender: TObject

Socket: TCustomWinSocket)

begin
memo1.Lines.Add('Client disconected.')
end


procedure TServerForm.CbControlClick(Sender: TObject)

begin
if CBControl.Checked then
begin
control:=true

memo1.Lines.Add('You are able to be controled by client now.')
end
else
begin
control:=false

memo1.lines.add('You are not able to be controled by client now.')

end

end


procedure TServerForm.ServerSocket1ClientError(Sender: TObject

Socket: TCustomWinSocket
ErrorEvent: TErrorEvent
var ErrorCode: Integer)

begin
showmessage(ServerSocket1.Socket.Connections[0].RemoteHost+#13#10+'未开机或未安装服务程序')

errorcode:=0

MemoryStream.Clear

receiving:=0

end


procedure TServerForm.EdtSendKeyPress(Sender: TObject
var Key: Char)

begin
if key=#13 then
begin
BtnSend.Click

EdtSend.Clear

end

end


procedure TServerForm.Button1Click(Sender: TObject)

begin
capture

end


procedure TServerForm.BtnClearClick(Sender: TObject)

begin
memo1.Clear

end


end.

来自: chenybin, 时间: 2005-08-15 21:16:47, ID: 3168018
TMemoryStream.truncate
或者
TMemoryStream.SetSize(0);看看,明天帮你调试

来自: ranjiao, 时间: 2005-08-15 21:33:39, ID: 3168035
多谢了楼上的~

刚开始用delphibbs 怎么追加分数?

来自: chenybin, 时间: 2005-08-15 21:36:24, ID: 3168038
不用追加,追加要重新开帖子,如果答案能满足你结贴就可以了,记得发分数给偶,细细[:D][:D][:D]

来自: ranjiao, 时间: 2005-08-19 9:39:08, ID: 3172471
还是不行啊 MemoryStream没有truncate 而我用setsize的话并没有真正清内存,还是会出错

来自: chenybin, 时间: 2005-08-20 2:58:49, ID: 3173788
方便的话留个联系方式,把代码发给我,我帮你调

来自: ranjiao, 时间: 2005-08-22 22:53:12, ID: 3176438
我的邮箱是ranjiao@gmail.com
这两天快开学了,可能回的会比较慢

问题讨论没有结束 ...
 
To BufferStream
你一个一个的读和写,有没有一次性的
WriteBuffer(buf^, strlen(buf))
//其中Buf为PChar类型,这样不是更方便吗

To weiliu
你从别人那抄一大堆,不累呀。那个东东我在没提问之前早就找到过啦,能不能按照我提的要求回答一下

虽然以上两位的结果并不是很让人满意,但还是非常感谢大家的参与,欢迎大家继续讨论
 
楼主知道还问?是倒分吗?
 
楼上的可真说错了,倒分那事我不干。
我只不过想把流这Delphi好使的玩意再弄懂点
 
var
stream: TStream;
str, SWriteError: string;
count: integer;
......
str:='hello,test';
SWriteError:='流写入错误';
count:=length(str);
stream:=TMemoryStream.Create;
try
stream.WriteBuffer(str, count);
//或:
//if (stream2.Write(str, count) <> Count) then
// raise EWriteError.CreateRes(@SWriteError)

...
finally
stream.free
end;

//WriteBuffer 实际上就是调用 Write 加上错误报告:
procedure TStream.WriteBuffer(const Buffer
Count: Longint);
begin
if (Count <> 0) and (Write(Buffer, Count) <> Count) then
raise EWriteError.CreateRes(@SWriteError);
end;
//ReadBuffer 也是同样道理:
procedure TStream.ReadBuffer(var Buffer
Count: Longint);
begin
if (Count <> 0) and (Read(Buffer, Count) <> Count) then
raise EReadError.CreateRes(@SReadError);
end;
 
楼上的在写下你的代码之前不知道有没有验证过正确性
您的那段WriteBuffer在写完以后,写是写了,可是真写的是Hello,Test吗?有验证过吗?
你不信保存到一个文件中去查看一下
 
http://www.delphibbs.com/keylife/iblog_show.asp?xid=16514
 
var mm:TMemoryStream;
p:PChar;
begin
p:='hello,test'#13#10;
mm:=TMemoryStream.Create;
mm.Write(p^,Length(p));//如果失败不会触发异常
mm.WriteBuffer(p^,Length(p));//如果失败会触发异常
mm.SaveToFile('C:/test.txt');
mm.Clear;
mm.Read(p^,mm.Size);
mm.Position:=mm.Size div 2;
ShowMessage(p);
mm.ReadBuffer(p^,mm.Size div 2);
ShowMessage(p);
mm.Free;

//如果用string代替Pchar则在Read或Write中需要指出首地址如
p:string;
p:='hello,test';
则mm.write(p[1],length(p))//貌似这样。
所以Buffer这个数据类型其实是堆中内存首个数据内容和接下来的连续逻辑上的Count(Count*sizeof(值类型))内存数据.
-----------------------------------------
在别人给你回答问题的时候最好先道谢,因为复制/粘贴也需要时间和精力。但是却并没有这个义务和任何好处。谢谢!
 
Write与WriteBuffer的区别:(Read与ReadBuffer的区别类似)
(1)Write返回写入的字节数,WriteBuffer无返回值
(2)WriteBuffer实际上是在调用Write的基础上,加一个错误捕捉,即当Write返回值不等于Count参数时,引发一个错误.
简单示例:
var
Str1,Str2:string;
begin
Str1:='hello,test';
with TMemoryStream.Create do
try
Write(Str1[1],Length(Str1))
//写入
SetLength(Str2,Size)

Seek(0,soFromBeginning)
//定位至Stream的开头,也可用Position:=0
Read(Str2[1],Size);
ShowMessage(Str2);
finally
Free;
end;
end;
 
To Rainstorey
在论坛中我们是需要很多热心者,但我觉得在程序的世界中更需要一个严谨的工作者,一个小的错误,望望能导致整个软件的瘫痪

再次感谢大家的热心帮助
 
多人接受答案了。
 
后退
顶部