http://blog.163.com/l1_jun/blog/static/143863882011111231928259/

delphi程序在自身EXE后(插入)追加文件、数据  

2011-12-12 15:19:28|  分类: Delphi|举报|字号 订阅

下载LOFTER客户端
 
 

制作两个程序:一个主程序,一个辅程序。主程序的作用是往辅程序的尾部添加资源,即.tex、.bmp等文件。辅程序则负责对这些资源进行处理,如显示、编辑等。以下是它们的例程。

主程序:

procedure TForm1.FormCreate(Sender: TObject);

var

Target,str:TFilestream;

Size:Integer;

Begin

try

str:=TFileStream.Create('My.bmp',fmOpenRead or fmShareExclusive);

Target := TFilestream.create('d:\Project1.exe', fmOpenWrite or fmShareExclusive);

// d:\Project1.exe为辅程序

Target.Seek(0,soFromEnd);

//往辅程序的尾部添加资源

Target.CopyFrom(str,0);

Size:=str.Size + Sizeof(Size);

//计算资源大小,并写入辅程序尾部

Target.WriteBuffer(Size,Sizeof(Size));

finally

Target.Free;

str.Free;

end;

end;

 

辅程序:

procedure TForm1.FormCreate(Sender: TObject);

var

Source:TFilestream;

str:TMemoryStream;

Size:Integer;

Begin

try

str:=TMemoryStream.Create;

Source := TFilestream.create(Application.ExeName, fmOpenRead or fmShareDenyNone);

Source.Seek(-Sizeof(Size),soFromEnd);

//读出资源大小

Source.ReadBuffer(Size,SizeOf(Size));

//定位到资源的开始位置

Source.Seek(-Size,soFromEnd);

//取出资源并存到文件中

str.CopyFrom(Source,Size - SizeOf(Size));

str.SaveToFile('Temp.bmp');

//显示

Image1.LoadFromFile('Temp.bmp');

Finally

str.Free;

Source.Free;

end;

end;

 

 

当然,上面的程序只是基础,但加以扩充。你就可以实现往Project1.exe中加入任意复杂的

数据,方法如下(其实也是压缩程序的原理之一):

首先你得定义两个记录:

TFileRec = record

name : shortstring;

start : longint;

Size:Longint;

end;

TArchiveRec = record

FileCount:longint;

end;

TFileRec用于记录每个文件的信息。(以上两个记录的具体内容可自定,但必须能确定

记录的大小,也即不能在记录中有string类型等不能确定大小的字段),

TArchiveRec用于记录插入文件的总个数。

往Project1.exe中添加资源时,可依照以上的方法进行,即把资源的数据一个一个地往

Project1.exe的尾部添加.但在加入一个资源之前,你必须先得到当前的位置(可通过

Target.Size或先移到Target的尾部,再通过Position属性得到),然后写入该文件对应

的TFileRec记录的Start字段,用于记录该资源在Project1.exe中的起始位置,在加入全部

资源以后,你再设置TArchiveRec记录的FileCount字段,然后按加入资源的顺序往Project1.exe

尾部写入对应的TFileRec,最后再写入TArchiveRec记录。从而完成了添加资源操作。

在Project1.exe中读资源时,要先在Project1.exe的尾部读出TArchiveRec记录以得到资源的

个数,然后再根据资源的个数依次读出TFileRec记录,从而得到每个文件的Start等信息,

这样就可以正确地读出每个资源的数据了。之所以可以这样读,是因为TArchiveRec和TFileRec记录

的大小是可以确定的(通过Sizeof函数),所以你可以正确定位。

其实这种程序的难点就是如何定位,只要实现了正确定位,那一切就OK了。

 

有一点错:

procedure TForm1.Button1Click(Sender: TObject);

var

Source:TFilestream;

str:TMemoryStream;

Size:Integer;

begin

try

str:=TMemoryStream.Create;

Source := TFilestream.create(Application.ExeName, fmOpenRead or fmShareDenyNone);

Source.Seek(-Sizeof(Size),soFromEnd);

//读出资源大小

Source.ReadBuffer(Size,SizeOf(Size));

//定位到资源的开始位置

Source.Seek(-Size,soFromEnd);

//取出资源并存到文件中

<font color=red> str.CopyFrom(Source,Size - SizeOf(Size)); </font>

<font color=blue> //上面这一句报错,说是'Stream read error'

//我执行的是被写入了图片的那个执行程序,对吗?</font>

 

str.SaveToFile('Temp.bmp');

//显示

Image1.Picture.LoadFromFile('Temp.bmp');

Finally

str.Free;

Source.Free;

end;

end;

-----------------追加数据例子----------------------------------------

?//写文件尾
procedure TForm1.Button1Click(Sender: TObject);
var
f:tfilestream;
buf1,temp:string;
buf: array [0..254] of char; 
i:integer;
begin
buf1 := edit1.Text;
for i := 1 to 255 do
begin
buf[i-1]:=buf1[i];
end;
f:=TfileStream.create(extractfilepath(application.ExeName)+'\test.exe',fmopenreadwrite);
f.position:=f.size;
f.write(buf,255);
f.free;
end;

//读文件尾
procedure TForm1.Button2Click(Sender: TObject);
var
f:tfilestream;
buf1:string;
buf: array [0..254] of char; 
i:integer;
begin
f:=TfileStream.create(extractfilepath(application.ExeName)+'\test.exe',fmopenread);
f.position:=f.size-255;
f.Read(buf,255);
f.free;

buf1:=buf;
//for i := 1 to 19 do
//begin
// buf1[i]:=buf[i-1];
//end;
edit2.Text := buf1;
end;