
(本图片由DeepAI自动生成)
一、概述
生成小型可执行文件最广泛使用的做法之一是将项目模块化为几个EXEs、DLLs、BPLs,并保持独立的辅助文本、图像或声音文件。
这种做法有助于减少系统更新时的文件流量,因为它只对那些实际改变了的文件进行更新。
然而,如果有必要为整个系统保留一个文件,Delphi通过其IDE提供了这种可能性。
在这篇文章中,我们将看看如何在可执行文件中插入外部文件,并在以后有必要时访问它们。
二、将文件添加到项目中
虽然这个功能从Delphi第三版开始就存在,但将外部文件纳入可执行文件的方式从2009版开始已经有了很大的改进。现在你可以使用一个资源管理器,可以通过菜单Project > Resources and Images访问。在截图1中,你可以看到通过资源管理器屏幕添加的几个文件。

一旦文件被添加,它们就会出现在Delphi的项目管理器中,你可以选择它们并在对象检查器中改变它们的属性,如屏幕截图2所示。

一旦文件被添加,项目被编译,就会生成一个扩展名为*.rc的文本文件。在每一行中,它包含一个 "别名 "来引用文件、其物理路径和资源数据类型。参照图2的这个文件的内容可以在下面的图片中看到。

该文件最终e在生成*.rc文件后,Delphi将其编译成扩展名为*.dres的中间版本,这将在链接过程中使用。
三、重复使用文本文件
不符合资源(位图、图标和字体文件)预定义标准的文件,如文本文件,被封装为一种叫做RCData的二进制类型。为了访问它们,有必要使用一个叫做TResourceStream的类,它允许你使用一个代码行将文件加载到任何具有TStrings类型属性的组件中。例如,我们可以很容易地加载文件的内容,并通过以下命令在ListBox中显示它们。
var
LStream : TResourceStream;
begin
LStream := TResourceStream.Create(HInstance, 'TXTuf', RT_RCDATA);
try
ListBox1.Items.LoadFromStream(LStream);
finally
LStream.free;
end;
end;
当你在调用TStrings类的LoadFromStream方法时实例化TResourceStream类时,有必要使用至少三个参数:一个名为HInstance的指针变量,引用资源的 "别名",以及一个代表资源在可执行文件中存储的数据类型的常量(例如:RT_RCDATA)。
四、重复使用图像文件
图像文件可以通过两种方式被重复使用,这取决于它们的类型。如果它们是图标图像、*.bmp文件或光标,有LoadFromResourceName方法,它允许你只用一行代码就能加载它们。
Image2.Picture.Bitmap.LoadFromResourceName(HInstance, 'IMGPredio');
请注意,由于这是一个以*.bmp为扩展名的图像,该方法不包含额外的转换程序,与其他格式的图像不同,这些图像是作为二进制文件编译的。
第二种方法用于处理PNG或JPEG图像。在这种情况下,有必要使用能够正确处理资源的类。我们可以在下面的例子中看到如何做到这一点。
procedure TFormExample.BtnImageClick(Sender: TObject);
var
PngImage: TPngImage;
begin
PngImage := TPngImage.Create;
try
PngImage.LoadFromResourceName(HInstance, 'IMGDevmediaLogo');
Image1.Picture.Graphic := PngImage;
finally
PngImage.Free;
end;
end;
第05行:我们实例化了一个TPngImage类型的对象。
第07行:LoadFromResourceName方法获得了被编译为RCData的*.png类型的图像的副本。
第08行:我们将png实例分配给Graphic属性,结果,组件复制了我们的png,图像显示在组件中;
第10行:我们释放TPngImage的本地对象以防止内存泄漏。
五、重复使用音频文件、可执行文件、DLLs和其他文件
除了我们到目前为止所考虑的那些类型之外,其他类型的文件也被编译为RCData,但是为了使用它们,你必须使用TResourceStream和TFileStream类的组合来提取它们,如下所示。在这个例子中,我们使用了一个MP3文件,但同样的代码也可以用于其他类型,比如可执行文件或DLLs。
procedure TFormExample.btnExecutarMP3(Sender: TObject);
var
ResourceStream: TResourceStream;
FileName: string;
MediaPlayer: TMediaPlayer;
begin
ResourceStream := TResourceStream.Create(hInstance, 'WAVClock', RT_RCDATA);
try
FileName := ExtractFilePath(Application.ExeName) + 'file.mp3';
ResourceStream.SaveToFile(FileName);
finally
ResourceStream.Free;
结论
尽管资源对于在可执行文件本身中运输文件和在系统中重复使用它们非常有用,但你应该小心使用它们。由于没有有效的文件压缩,其大小通常比预期的要大。 end;
MediaPlayer.Close;
MediaPlayer.FileName := FileName;
MediaPlayer.Open;
MediaPlayer.Play;
end;
第07行:我们实例化一个TResourceStream,把MP3文件的别名和数据类型(RCData)作为一个参数传给它。
第09行:我们把提取文件的目录路径分配给字符串变量。
第10行和第11行:我们将第7行中加载的资源的所有内容保存到文件中。
第15至18行:我们执行从可执行文件中提取的MP3文件。
六、结论
尽管资源对于在可执行文件本身中传输文件和在系统中重复使用它们非常有用,但还是应该小心使用它们。由于没有有效的文件压缩,其大小通常比预期的要大。
七、译者注:
关于作者的结论,认为资源文件没有有效的压缩,这个其实是可以进行压缩的,Delphi有提供TZipFile类来进行压缩和解压缩。只是操作起来稍微有点麻烦,也就是说在增加资源前先对资源进行压缩,具体使用的时候,可以使用Delphi的TZipFile进行动态解压(支持内存流解压),然后就可以使用。