在我的过程系列中,我向您展示了如何在后台进行非阻塞处理。这是一个实际案例:从 Internet 下载文件。
在开发链接到第三方网站或 API 的移动应用程序或办公应用程序时,必须访问远程文件的情况并不少见。下载它们的最简单方法是使用 System.Net.HttpClient 单元的组件执行 GET。
这是一个允许从 URL 检索文件并将其存储在本地的类。
unit u_download;
interface
uses system.SysUtils;
type
tdownload_file = class(tobject)
class procedure download(from_url, to_filename: string;
success: tproc = nil; error: tproc = nil);
class function temporaryFileName(appName: string): string;
end;
implementation
{ download_file }
uses system.ioutils, system.Net.HttpClient, system.Classes;
class procedure tdownload_file.download(from_url, to_filename: string;
success: tproc = nil; error: tproc = nil);
begin
tthread.CreateAnonymousThread(
procedure
var
serveur: THTTPClient;
serveur_reponse: IHTTPResponse;
fichier: tfilestream;
begin
try
serveur := THTTPClient.Create;
try
serveur_reponse := serveur.Get(from_url);
if serveur_reponse.StatusCode = 200 then
begin
fichier := tfilestream.Create(to_filename,
fmCreate or fmOpenWrite or fmShareDenyWrite);
try
fichier.CopyFrom(serveur_reponse.ContentStream,
serveur_reponse.ContentStream.Size);
finally
fichier.Free;
end;
if assigned(success) then
tthread.queue(nil,
procedure
begin
success;
end);
end
else
begin
raise Exception.CreateFmt
('Cannot get distant file. Please contact us or retry later. HTTP %d - %s',
[serveur_reponse.StatusCode, serveur_reponse.StatusText]);
end;
finally
serveur.Free;
end;
except
if assigned(error) then
tthread.queue(nil,
procedure
begin
error;
end);
end;
end).Start;
end;
class function tdownload_file.temporaryFileName(appName: string): string;
begin
result := tpath.Combine(tpath.gettempPath,
appName + '-' + datetimetotimestamp(now).Time.ToString + '.tmp')
end;
end.
由于我们想知道下载的结果,尤其是在下载结束时,还有什么比在必要时还要执行将调用的过程更好的呢?
因此,调用如下:
procedure TForm1.Button1Click(Sender: TObject);
begin
Button1.Enabled := false;
tdownload_file.download('http://gamolf.fr/images/gamolf-500x500.png',
tpath.Combine(tpath.GetDocumentsPath(), '__monimage.png'),
procedure
begin
showMessage('Fichier téléchargé');
Button1.Enabled := true;
end,
procedure
begin
showMessage('Erreur lors du téléchargement');
Button1.Enabled := true;
end);
end;
在这个例子中,我只是在一个空表单上放置了一个 TButton。此按钮的 onclick 事件链接到 Button1Click 方法。该单元使用另外两个单元:用于下载的 u_download 和 System.IOUtils,其类 TPath 允许根据运行程序的平台获取有用文件列表。
当按钮被点击时,它被停用以防止它再次被点击,直到操作完成,然后调用指定 URL 的图像(这里是我的一个站点的标志)和本地存储文件夹的下载。此调用还传递两个匿名过程。在这些过程中,会显示警告用户传输状态,并且按钮状态会重新激活。
在这里,重新激活按钮是没有用的,因为再次单击它会下载相同的文件,但您可以看到原理。
当下载成功完成时,将调用作为参数传递的第一个过程。在发生错误时调用第二个:当引发异常时或者如果存在除 200 以外的 HTTP 错误代码,因为在这种情况下我们自己引发了异常。
它们在主进程中执行,因此提供对图形功能的访问,例如可视化组件或对话框。
注意他们的调用是如何在源中处理的:
class procedure tdownload_file.download(from_url, to_filename: string;
success: tproc = nil; error: tproc = nil);
我们首先在进行下载的方法中声明两个类型为 TProc 的参数,如果未指定参数,我们将它们默认设置为 nil。确实可能发生在成功或错误的情况下我们无所事事,让最终的程序员选择是否使用它们。请注意,如果您想使用错误函数而不是成功函数,您仍然必须将参数传递给 nil,因为编译器将无法猜测您要跳过此参数。
当我们要调用它们时,我们测试是否指示了参数。assigned () 方法允许您知道某个指针是否指向某处,但不一定知道该某处是否有效,因此请注意并记住在释放对象时使用 FreeAndNil (myObjet) 而不仅仅是 myObjet.Free () 。最后,我们通过TThread.Queue()方法在提交给主线程的过程中调用成功或错误过程。
if assigned(success) then
tthread.queue(nil,
procedure
begin
success;
end);
这样就获得了一个代码,它可以在不中断程序运行的情况下简单地下载任何远程文件,同时能够在下载结束时采取行动。
Copyright © 2014 DelphiW.com 开发 源码 文档 技巧 All Rights Reserved
晋ICP备14006235号-8 晋公网安备 14108102000087号
执行时间: 0.047801971435547 seconds