在Delphi 7开发下有强大的Indy控件,版本为9,要实现一个FTP服务器,参考自带的例子,发现还要写很多函数,而且不支持中文显示文件列表等等。

于是,自己改进封装了下,形成一个TFTPServer类。

源码如下:

 {*******************************************************}
{ }
{ 系统名称 FTP服务器类 }
{ 版权所有 (C) http://blog.csdn.net/akof1314 }
{ 单元名称 FTPServer.pas }
{ 单元功能 在Delphi 7下TIdFTPServer实现FTP服务器 }
{ }
{*******************************************************}
unit FTPServer; interface uses
Classes, Windows, Sysutils, IdFTPList, IdFTPServer, Idtcpserver, IdSocketHandle, Idglobal, IdHashCRC, IdStack;
{-------------------------------------------------------------------------------
功能: 自定义消息,方便与窗体进行消息传递
-------------------------------------------------------------------------------}
type
TFtpNotifyEvent = procedure (ADatetime: TDateTime;AUserIP, AEventMessage: string) of object;
{-------------------------------------------------------------------------------
功能: FTP服务器类
-------------------------------------------------------------------------------}
type
TFTPServer = class
private
FUserName,FUserPassword,FBorrowDirectory: string;
FBorrowPort: Integer;
IdFTPServer: TIdFTPServer;
FOnFtpNotifyEvent: TFtpNotifyEvent;
procedure IdFTPServer1UserLogin( ASender: TIdFTPServerThread; const AUsername, APassword: string; var AAuthenticated: Boolean ) ;
procedure IdFTPServer1ListDirectory( ASender: TIdFTPServerThread; const APath: string; ADirectoryListing: TIdFTPListItems ) ;
procedure IdFTPServer1RenameFile( ASender: TIdFTPServerThread; const ARenameFromFile, ARenameToFile: string ) ;
procedure IdFTPServer1RetrieveFile( ASender: TIdFTPServerThread; const AFilename: string; var VStream: TStream ) ;
procedure IdFTPServer1StoreFile( ASender: TIdFTPServerThread; const AFilename: string; AAppend: Boolean; var VStream: TStream ) ;
procedure IdFTPServer1RemoveDirectory( ASender: TIdFTPServerThread; var VDirectory: string ) ;
procedure IdFTPServer1MakeDirectory( ASender: TIdFTPServerThread; var VDirectory: string ) ;
procedure IdFTPServer1GetFileSize( ASender: TIdFTPServerThread; const AFilename: string; var VFileSize: Int64 ) ;
procedure IdFTPServer1DeleteFile( ASender: TIdFTPServerThread; const APathname: string ) ;
procedure IdFTPServer1ChangeDirectory( ASender: TIdFTPServerThread; var VDirectory: string ) ;
procedure IdFTPServer1CommandXCRC( ASender: TIdCommand ) ;
procedure IdFTPServer1DisConnect( AThread: TIdPeerThread ) ;
protected
function TransLatePath( const APathname, homeDir: string ) : string;
public
constructor Create; reintroduce;
destructor Destroy; override;
procedure Run;
procedure Stop;
function GetBindingIP():string;
property UserName: string read FUserName write FUserName;
property UserPassword: string read FUserPassword write FUserPassword;
property BorrowDirectory: string read FBorrowDirectory write FBorrowDirectory;
property BorrowPort: Integer read FBorrowPort write FBorrowPort;
property OnFtpNotifyEvent: TFtpNotifyEvent read FOnFtpNotifyEvent write FOnFtpNotifyEvent;
end; implementation {-------------------------------------------------------------------------------
过程名: TFTPServer.Create
功能: 创建函数
参数: 无
返回值: 无
-------------------------------------------------------------------------------}
constructor TFTPServer.Create;
begin
IdFTPServer := tIdFTPServer.create( nil ) ;
IdFTPServer.DefaultPort := ; //默认端口号
IdFTPServer.AllowAnonymousLogin := False; //是否允许匿名登录
IdFTPServer.EmulateSystem := ftpsUNIX;
IdFTPServer.HelpReply.text := '帮助还未实现!';
IdFTPServer.OnChangeDirectory := IdFTPServer1ChangeDirectory;
IdFTPServer.OnGetFileSize := IdFTPServer1GetFileSize;
IdFTPServer.OnListDirectory := IdFTPServer1ListDirectory;
IdFTPServer.OnUserLogin := IdFTPServer1UserLogin;
IdFTPServer.OnRenameFile := IdFTPServer1RenameFile;
IdFTPServer.OnDeleteFile := IdFTPServer1DeleteFile;
IdFTPServer.OnRetrieveFile := IdFTPServer1RetrieveFile;
IdFTPServer.OnStoreFile := IdFTPServer1StoreFile;
IdFTPServer.OnMakeDirectory := IdFTPServer1MakeDirectory;
IdFTPServer.OnRemoveDirectory := IdFTPServer1RemoveDirectory;
IdFTPServer.Greeting.Text.Text := '欢迎进入FTP服务器';
IdFTPServer.Greeting.NumericCode := ;
IdFTPServer.OnDisconnect := IdFTPServer1DisConnect;
with IdFTPServer.CommandHandlers.add do
begin
Command := 'XCRC'; //可以迅速验证所下载的文档是否和源文档一样
OnCommand := IdFTPServer1CommandXCRC;
end;
end;
{-------------------------------------------------------------------------------
过程名: CalculateCRC
功能: 计算CRC
参数: const path: string
返回值: string
-------------------------------------------------------------------------------}
function CalculateCRC( const path: string ) : string;
var
f: tfilestream;
value: dword;
IdHashCRC32: TIdHashCRC32;
begin
IdHashCRC32 := nil;
f := nil;
try
IdHashCRC32 := TIdHashCRC32.create;
f := TFileStream.create( path, fmOpenRead or fmShareDenyWrite ) ;
value := IdHashCRC32.HashValue( f ) ;
result := inttohex( value, ) ;
finally
f.free;
IdHashCRC32.free;
end;
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.IdFTPServer1CommandXCRC
功能: XCRC命令
参数: ASender: TIdCommand
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.IdFTPServer1CommandXCRC( ASender: TIdCommand ) ;
// note, this is made up, and not defined in any rfc.
var
s: string;
begin
with TIdFTPServerThread( ASender.Thread ) do
begin
if Authenticated then
begin
try
s := ProcessPath( CurrentDir, ASender.UnparsedParams ) ;
s := TransLatePath( s, TIdFTPServerThread( ASender.Thread ) .HomeDir ) ;
ASender.Reply.SetReply( , CalculateCRC( s ) ) ;
except
ASender.Reply.SetReply( , 'file error' ) ;
end;
end;
end;
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.Destroy
功能: 析构函数
参数: 无
返回值: 无
-------------------------------------------------------------------------------}
destructor TFTPServer.Destroy;
begin
IdFTPServer.free;
inherited destroy;
end; function StartsWith( const str, substr: string ) : boolean;
begin
result := copy( str, , length( substr ) ) = substr;
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.Run
功能: 开启服务
参数: 无
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.Run;
begin
IdFTPServer.DefaultPort := BorrowPort;
IdFTPServer.Active := True;
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.Stop
功能: 关闭服务
参数: 无
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.Stop;
begin
IdFTPServer.Active := False;
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.GetBindingIP
功能: 获取绑定的IP地址
参数:
返回值: string
-------------------------------------------------------------------------------}
function TFTPServer.GetBindingIP():string ;
begin
Result := GStack.LocalAddress;
end;
{-------------------------------------------------------------------------------
过程名: BackSlashToSlash
功能: 反斜杠到斜杠
参数: const str: string
返回值: string
-------------------------------------------------------------------------------}
function BackSlashToSlash( const str: string ) : string;
var
a: dword;
begin
result := str;
for a := to length( result ) do
if result[a] = '/' then
result[a] := '/';
end; {-------------------------------------------------------------------------------
过程名: SlashToBackSlash
功能: 斜杠到反斜杠
参数: const str: string
返回值: string
-------------------------------------------------------------------------------}
function SlashToBackSlash( const str: string ) : string;
var
a: dword;
begin
result := str;
for a := to length( result ) do
if result[a] = '/' then
result[a] := '/';
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.TransLatePath
功能: 路径名称翻译
参数: const APathname, homeDir: string
返回值: string
-------------------------------------------------------------------------------}
function TFTPServer.TransLatePath( const APathname, homeDir: string ) : string;
var
tmppath: string;
begin
result := SlashToBackSlash(Utf8ToAnsi(homeDir) ) ;
tmppath := SlashToBackSlash( Utf8ToAnsi(APathname) ) ;
if homedir = '/' then
begin
result := tmppath;
exit;
end; if length( APathname ) = then
exit;
if result[length( result ) ] = '/' then
result := copy( result, , length( result ) - ) ;
if tmppath[] <> '/' then
result := result + '/';
result := result + tmppath;
end; {-------------------------------------------------------------------------------
过程名: GetNewDirectory
功能: 得到新目录
参数: old, action: string
返回值: string
-------------------------------------------------------------------------------}
function GetNewDirectory( old, action: string ) : string;
var
a: integer;
begin
if action = '../' then
begin
if old = '/' then
begin
result := old;
exit;
end;
a := length( old ) - ;
while ( old[a] <> '/' ) and ( old[a] <> '/' ) do
dec( a ) ;
result := copy( old, , a ) ;
exit;
end;
if ( action[] = '/' ) or ( action[] = '/' ) then
result := action
else
result := old + action;
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.IdFTPServer1UserLogin
功能: 允许服务器执行一个客户端连接的用户帐户身份验证
参数: ASender: TIdFTPServerThread; const AUsername, APassword: string; var AAuthenticated: Boolean
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.IdFTPServer1UserLogin( ASender: TIdFTPServerThread;
const AUsername, APassword: string; var AAuthenticated: Boolean ) ;
begin
AAuthenticated := ( AUsername = UserName ) and ( APassword = UserPassword ) ;
if not AAuthenticated then
exit;
ASender.HomeDir := AnsiToUtf8(BorrowDirectory);
asender.currentdir := '/';
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'用户登录服务器');
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.IdFTPServer1ListDirectory
功能: 允许服务器生成格式化的目录列表
参数: ASender: TIdFTPServerThread; const APath: string; ADirectoryListing: TIdFTPListItems
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.IdFTPServer1ListDirectory( ASender: TIdFTPServerThread; const APath: string; ADirectoryListing: TIdFTPListItems ) ; procedure AddlistItem( aDirectoryListing: TIdFTPListItems; Filename: string; ItemType: TIdDirItemType; size: int64; date: tdatetime ) ;
var
listitem: TIdFTPListItem;
begin
listitem := aDirectoryListing.Add;
listitem.ItemType := ItemType; //表示一个文件系统的属性集
listitem.FileName := AnsiToUtf8(Filename); //名称分配给目录中的列表项,这里防止了中文乱码
listitem.OwnerName := 'anonymous';//代表了用户拥有的文件或目录项的名称
listitem.GroupName := 'all'; //指定组名拥有的文件名称或目录条目
listitem.OwnerPermissions := 'rwx'; //拥有者权限,R读W写X执行
listitem.GroupPermissions := 'rwx'; //组拥有者权限
listitem.UserPermissions := 'rwx'; //用户权限,基于用户和组权限
listitem.Size := size;
listitem.ModifiedDate := date;
end; var
f: tsearchrec;
a: integer;
begin
ADirectoryListing.DirectoryName := apath;
a := FindFirst( TransLatePath( apath, ASender.HomeDir ) + '*.*', faAnyFile, f ) ;
while ( a = ) do
begin
if ( f.Attr and faDirectory > ) then
AddlistItem( ADirectoryListing, f.Name, ditDirectory, f.size, FileDateToDateTime( f.Time ) )
else
AddlistItem( ADirectoryListing, f.Name, ditFile, f.size, FileDateToDateTime( f.Time ) ) ;
a := FindNext( f ) ;
end; FindClose( f ) ;
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.IdFTPServer1RenameFile
功能: 允许服务器重命名服务器文件系统中的文件
参数: ASender: TIdFTPServerThread; const ARenameFromFile, ARenameToFile: string
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.IdFTPServer1RenameFile( ASender: TIdFTPServerThread;
const ARenameFromFile, ARenameToFile: string ) ;
begin
try
if not MoveFile( pchar( TransLatePath( ARenameFromFile, ASender.HomeDir ) ) , pchar( TransLatePath( ARenameToFile, ASender.HomeDir ) ) ) then
RaiseLastOSError;
except
on e:Exception do
begin
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'重命名文件[' + Utf8ToAnsi(ARenameFromFile) + ']失败,原因是' + e.Message);
Exit;
end;
end;
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'重命名文件[' + Utf8ToAnsi(ARenameFromFile) + ']为[' + Utf8ToAnsi(ARenameToFile) + ']');
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.IdFTPServer1RetrieveFile
功能: 允许从服务器下载文件系统中的文件
参数: ASender: TIdFTPServerThread; const AFilename: string; var VStream: TStream
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.IdFTPServer1RetrieveFile( ASender: TIdFTPServerThread;
const AFilename: string; var VStream: TStream ) ;
begin
VStream := TFileStream.Create( translatepath( AFilename, ASender.HomeDir ) , fmopenread or fmShareDenyWrite ) ;
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'下载文件[' + Utf8ToAnsi(AFilename) + ']');
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.IdFTPServer1StoreFile
功能: 允许在服务器上传文件系统中的文件
参数: ASender: TIdFTPServerThread; const AFilename: string; AAppend: Boolean; var VStream: TStream
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.IdFTPServer1StoreFile( ASender: TIdFTPServerThread;
const AFilename: string; AAppend: Boolean; var VStream: TStream ) ;
begin
if FileExists( translatepath( AFilename, ASender.HomeDir ) ) and AAppend then
begin
VStream := TFileStream.create( translatepath( AFilename, ASender.HomeDir ) , fmOpenWrite or fmShareExclusive ) ;
VStream.Seek( , soFromEnd ) ;
end
else
VStream := TFileStream.create( translatepath( AFilename, ASender.HomeDir ) , fmCreate or fmShareExclusive ) ;
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'上传文件[' + Utf8ToAnsi(AFilename) + ']');
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.IdFTPServer1RemoveDirectory
功能: 允许服务器在服务器删除文件系统的目录
参数: ASender: TIdFTPServerThread; var VDirectory: string
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.IdFTPServer1RemoveDirectory( ASender: TIdFTPServerThread;
var VDirectory: string ) ;
begin
try
RmDir( TransLatePath( VDirectory, ASender.HomeDir ) ) ;
except
on e:Exception do
begin
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'删除目录[' + Utf8ToAnsi(VDirectory) + ']失败,原因是' + e.Message);
Exit;
end;
end;
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'删除目录[' + Utf8ToAnsi(VDirectory) + ']');
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.IdFTPServer1MakeDirectory
功能: 允许服务器从服务器中创建一个新的子目录
参数: ASender: TIdFTPServerThread; var VDirectory: string
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.IdFTPServer1MakeDirectory( ASender: TIdFTPServerThread;
var VDirectory: string ) ;
begin
try
MkDir( TransLatePath( VDirectory, ASender.HomeDir ) ) ;
except
on e:Exception do
begin
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'创建目录[' + Utf8ToAnsi(VDirectory) + ']失败,原因是' + e.Message);
Exit;
end;
end;
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'创建目录[' + Utf8ToAnsi(VDirectory) + ']');
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.IdFTPServer1GetFileSize
功能: 允许服务器检索在服务器文件系统的文件的大小
参数: ASender: TIdFTPServerThread; const AFilename: string; var VFileSize: Int64
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.IdFTPServer1GetFileSize( ASender: TIdFTPServerThread;
const AFilename: string; var VFileSize: Int64 ) ;
begin
VFileSize := FileSizeByName( TransLatePath( AFilename, ASender.HomeDir ) ) ;
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'获取文件大小');
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.IdFTPServer1DeleteFile
功能: 允许从服务器中删除的文件系统中的文件
参数: ASender: TIdFTPServerThread; const APathname: string
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.IdFTPServer1DeleteFile( ASender: TIdFTPServerThread;
const APathname: string ) ;
begin
try
DeleteFile( pchar( TransLatePath( ASender.CurrentDir + '/' + APathname, ASender.HomeDir ) ) ) ;
except
on e:Exception do
begin
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'删除文件[' + Utf8ToAnsi(APathname) + ']失败,原因是' + e.Message);
Exit;
end;
end;
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'删除文件[' + Utf8ToAnsi(APathname) + ']');
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.IdFTPServer1ChangeDirectory
功能: 允许服务器选择一个文件系统路径
参数: ASender: TIdFTPServerThread; var VDirectory: string
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.IdFTPServer1ChangeDirectory( ASender: TIdFTPServerThread;
var VDirectory: string ) ;
begin
VDirectory := GetNewDirectory( ASender.CurrentDir, VDirectory ) ;
if Assigned(FOnFtpNotifyEvent) then
OnFtpNotifyEvent(Now, ASender.Connection.Socket.Binding.PeerIP,'进入目录[' + Utf8ToAnsi(VDirectory) + ']');
end; {-------------------------------------------------------------------------------
过程名: TFTPServer.IdFTPServer1DisConnect
功能: 失去网络连接
参数: AThread: TIdPeerThread
返回值: 无
-------------------------------------------------------------------------------}
procedure TFTPServer.IdFTPServer1DisConnect( AThread: TIdPeerThread ) ;
begin
// nothing much here
end;
end.

使用工程示例:

 unit Unit1; 

 interface 

 uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, FTPServer; type
TForm1 = class(TForm)
btn1: TButton;
btn2: TButton;
edt_BorrowDirectory: TEdit;
lbl1: TLabel;
mmo1: TMemo;
lbl2: TLabel;
edt_BorrowPort: TEdit;
lbl3: TLabel;
edt_UserName: TEdit;
lbl4: TLabel;
edt_UserPassword: TEdit;
procedure btn1Click(Sender: TObject);
procedure btn2Click(Sender: TObject);
procedure TFTPServer1FtpNotifyEvent(ADatetime: TDateTime;AUserIP, AEventMessage: string);
private
FFtpServer: TFTPServer;
public
{ Public declarations }
end; var
Form1: TForm1; implementation {$R *.dfm} procedure TForm1.btn1Click(Sender: TObject);
begin
if not Assigned(FFtpServer) then
begin
FFtpServer := TFTPServer.Create;
FFtpServer.UserName := Trim(edt_UserName.Text);
FFtpServer.UserPassword := Trim(edt_UserPassword.Text);
FFtpServer.BorrowDirectory := Trim(edt_BorrowDirectory.Text);
FFtpServer.BorrowPort := StrToInt(Trim(edt_BorrowPort.Text));
FFtpServer.OnFtpNotifyEvent := TFTPServer1FtpNotifyEvent;
FFtpServer.Run;
mmo1.Lines.Add(DateTimeToStr(Now) + # +'FTP服务器已开启,本机IP地址:' + FFtpServer.GetBindingIP);
end;
end; procedure TForm1.btn2Click(Sender: TObject);
begin
if Assigned(FFtpServer) then
begin
FFtpServer.Stop;
FreeAndNil(FFtpServer);
mmo1.Lines.Add(DateTimeToStr(Now) + # +'FTP服务器已关闭');
end;
end; procedure TForm1.TFTPServer1FtpNotifyEvent(ADatetime: TDateTime;AUserIP, AEventMessage: string);
begin
mmo1.Lines.Add(DateTimeToStr(ADatetime) + # + AUserIP + # + AEventMessage);
SendMessage(mmo1.Handle,WM_VSCROLL,SB_PAGEDOWN,);
end;
end.

结果如下图所示:

示例工程源码下载:

http://download.csdn.net/source/3236325

原博客地址:

http://blog.csdn.net/akof1314/article/details/6371984#comments

https://www.cnblogs.com/findumars/p/6360865.html

Delphi - Indy TIdFTPServer封装类的更多相关文章

  1. [delphi]indy idhttp post方法

    网易 博客 LOFTCam-用心创造滤镜 LOFTER-最美图片社交APP 送20张免费照片冲印 > 注册登录  加关注 techiepc的博客 万事如意 首页 日志 LOFTER 相册 音乐 ...

  2. Delphi Indy IDHttp 403 forbidden

    http://hbk777.blog.163.com/blog/static/6058086200681594333361/ Delphi Indy IDHttp 403 forbidden 2006 ...

  3. Indy9的TIdFTPServer封装类

    在Delphi 7开发下有强大的Indy控件,版本为9,要实现一个FTP服务器,参考自带的例子,发现还要写很多函数,而且不支持中文显示文件列表等等.于是,自己改进封装了下,形成一个TFTPServer ...

  4. delphi indy Idhttp error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert protocol version

    在使用 indy 中的 idhttp 组件访问 https 网站时,出现如下错误: error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert pr ...

  5. Delphi indy线程控件TIdThreadComponent的使用

    当程序需要做耗时操作,例如访问数据库获取较多的数据.获取大文件MD5.网络访问数据量比较大.界面需要频繁刷新等等,都可以用线程来解决界面卡顿的问题,从而优化用户体验. 在知道TIdThreadComp ...

  6. Delphi - Indy TIdHTTP方式创建程序外壳 - 实现可执行程序的自动升级

    Delphi 实现可执行程序的自动升级 准备工作: 1:Delphi调用TIdHTTP方式开发程序,生成程序打包外壳 说明:程序工程命名为ERP_Update 界面布局如下: 代码实现如下: unit ...

  7. Delphi - Indy TIdThreadComponent 线程研究

    Indy IdThreadComponent 线程研究 前几天在开发数据实时解析功能模块的时候,发现解析数据量巨大,特别耗时,程序一跑起来界面假死. 为了优化用户体验,采用了Indy 自带的IdThr ...

  8. Delphi - Indy 创建邮件自动发送服务

    服务器自动邮件线程 功能:此程序主要实现对Oracle数据库表tableName(存放需要发送邮件的相关信息)里面相关信息的邮件发送. 优点:开发人员可以直接再数据库后台对tableName表进行插入 ...

  9. Delphi - Indy TIdMessage和TIdSMTP实现邮件的发送

    idMessage / idSMTP 首先对idMessage类的各种属性进行赋值(邮件的基本信息,如收件人.邮件主题.邮件正文等),其次通过idSMTP连接邮箱服务器,最后通过idSMTP的Send ...

随机推荐

  1. jquery 操作HTML data全局属性缓存的坑

    data-* 全局属性 是一类被称为自定义数据属性的属性,它赋予我们在所有 HTML 元素上嵌入自定义数据属性的能力,并可以通过脚本(一般指JavaScript) 与 HTML 之间进行专有数据的交换 ...

  2. session对象和cookie对象的区别

    1.cookie数据存放在客户的浏览器上,session数据放在服务器上2.cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session3.ses ...

  3. sass的核心知识及使用

    sass的官方链接地址:htpp://sass-lang.com 参考链接地址:http://www.haorooms.com/post/sass_css 1. 基础语法 1.1 变量 SASS允许使 ...

  4. Is it a full physical image???

    My friend asked me why she could not find some important files in a physical image acquired from an ...

  5. what is the CCA?

    Clear Channel Assessment (CCA) is one of two carrier sense mechanisms in WLAN (or WiFi). It is defin ...

  6. 虚拟机安装CentOS的简短教程

    说明: 为什么要学Linux?因为现在互联网产品普遍使用Linux作为服务器系统. 测试工程师要学Linux吗?要,因为你会需要跟服务器打交道. 什么情况下测试工程师会跟服务器打交道?你可能要去部署测 ...

  7. GoAccess 分析 Nginx 日志

    0x00 事件 帮助朋友搭建了博客,运行过了一段时间,准备发个网站分析报告给他. 有效的数据只有 Nginx 的访问日志,于是使用决定 GoAccess 工具对这个日志进行分析, 0x01 安装 吾使 ...

  8. hdu6703_array

    题意 给定一个1到\(n\)的全排列,两种操作,将\(a_{pos}\)修改为\(a_{pos}+1000000\),询问第一个大于等于\(k\)的且不在\(a_1...a_r\)的数. 分析 由于\ ...

  9. Day 07--最终修改(三)

    2.明天着重学一下逻辑层的语法,以及界面层的数据绑定,与队友交流进度 3.今天修改也终于完成,除了搞c++以外的全部身心都放在这个东西身上也觉得它有点难搞,说明计算机不是吃素的.甚至在使用xml语法的 ...

  10. DBUtils框架的使用(下)

    刚才讲了使用QueryRunner插入.修改.更新数据,现在来学习一下使用QueryRunner进行数据库表查询. 通过QueryRunner类的query()方法即可完成数据库表的查询操作,但是在查 ...