PB实现自动更新客户端文件

C/S相较B/S结构的缺点是客户端文件更新比较烦琐,现用PB12.5实现客户端文件自动更新。

基本思路是:先将需要更新的文件上传到服务器数据库,文件最后修改时间存入字段[UpTime];客户端扫描数据库如果发现文件修改日期晚于本地文件的修改日期则下载更新该文件。

例程下载:https://download.csdn.net/download/nhwatertao/11807209

-- 数据库存储文件的表T_appdata
CREATE TABLE [dbo].[T_appdata](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [app] [varchar](50) NULL,
    [FileName] [varchar](100) NULL,
    [UpTime] [smalldatetime] NULL,
    [Uppsn] [varchar](50) NULL,
    [FileData] [image] NULL,
    [FileBytes] [int] NULL);

申明win32 API读取/设置文件日期函数,有关功能封装在自定对象中n_cst_filetime(附:n_cst_filetime.sru)。

$PBExportHeader$n_cst_filetime.sru
$PBExportComments$与文件时间有关的外部函数
forward
global type n_cst_filetime from nonvisualobject
end type
type os_filedatetime from structure within n_cst_filetime
end type
type os_fileopeninfo from structure within n_cst_filetime
end type
type os_finddata from structure within n_cst_filetime
end type
type os_securityattributes from structure within n_cst_filetime
end type
type os_systemtime from structure within n_cst_filetime
end type
end forward

type os_filedatetime from structure 
    unsignedlong        ul_lowdatetime 
    unsignedlong        ul_highdatetime 
end type 

type os_fileopeninfo from structure 
    character        c_length 
    character        c_fixed_disk 
    unsignedinteger        ui_dos_error 
    unsignedinteger        ui_na1 
    unsignedinteger        ui_na2 
    character        c_pathname[128] 
end type 

type os_finddata from structure 
    unsignedlong        ul_fileattributes 
    os_filedatetime        str_creationtime 
    os_filedatetime        str_lastaccesstime 
    os_filedatetime        str_lastwritetime 
    unsignedlong        ul_filesizehigh 
    unsignedlong        ul_filesizelow 
    unsignedlong        ul_reserved0 
    unsignedlong        ul_reserved1 
    character        ch_filename[260] 
    character        ch_alternatefilename[14] 
end type 

type os_securityattributes from structure 
    unsignedlong        ul_length 
    string        ch_description 
    boolean        b_inherit 
end type 

type os_systemtime from structure 
    unsignedinteger        ui_wyear 
    unsignedinteger        ui_wmonth 
    unsignedinteger        ui_wdayofweek 
    unsignedinteger        ui_wday 
    unsignedinteger        ui_whour 
    unsignedinteger        ui_wminute 
    unsignedinteger        ui_wsecond 
    unsignedinteger        ui_wmilliseconds 
end type 

global type n_cst_filetime from nonvisualobject autoinstantiate
end type

type prototypes
//  打开文件,返回文件句柄 =0失败
FUNCTION ulong CreateFile(ref string lpFileName, long dwDesiredAccess, long dwShareMode, long lpSecurityAttr, long dwCreationDisposition, long dwFlagsAndAttributes, long hTemplateFile) LIBRARY "kernel32.dll" ALIAS FOR "CreateFileA;ANSI"
FUNCTION boolean CloseHandle(long file_hand) LIBRARY "kernel32.dll" 

Function ulong GetFileTime(long hFile, ref os_filedatetime  lpCreationTime, ref os_filedatetime  lpLastAccessTime, ref os_filedatetime  lpLastWriteTime  )  library "kernel32.dll" 
Function ulong SetFileTime(long hFile, ref os_filedatetime  lpCreationTime, ref os_filedatetime  lpLastAccessTime, ref os_filedatetime  lpLastWriteTime  )  library "kernel32.dll" 

Function boolean FileTimeToSystemTime(ref os_filedatetime lpFileTime, ref os_systemtime lpSystemTime) library "kernel32.dll" 
Function boolean SystemTimeToFileTime(os_systemtime lpSystemTime, ref os_filedatetime lpFileTime) library "kernel32.dll" 
Function boolean FileTimeToLocalFileTime(ref os_filedatetime lpFileTime, ref os_filedatetime lpLocalFileTime) library "kernel32.dll" 
Function boolean LocalFileTimeToFileTime(ref os_filedatetime lpLocalFileTime, ref os_filedatetime lpFileTime) library "kernel32.dll" 

//  文件操作根据文件名查找文件。 
Function long    FindFirstFileA (ref string filename, ref os_finddata findfiledata) library "kernel32.dll" ALIAS FOR "FindFirstFileA;ANSI"
Function boolean FindNextFileA (long handle, ref os_finddata findfiledata) library "kernel32.dll" 
Function boolean FindClose (long handle) library "kernel32.dll" 
//Function long    OpenFile (ref string filename, ref os_fileopeninfo of_struct, ulong action) LIBRARY "kernel32.dll" 


//  取硬盘序列号 of_GetVolumeSerialNumber()
Function boolean GetVolumeInformationA(ref String ls_Rootpath, ref String ls_volumnename, Ulong lul_VolumeNameSize, ref Ulong lul_VolumeSerialNumber,&
   ref Ulong lul_MaximumComponentLength, ref Ulong lul_FileSystemFlags, ref String ls_FileSystemNameBuffer,Ulong lul_FileSystemNameSize) &
   Library "Kernel32.dll" Alias for "GetVolumeInformationA;ansi"
//  取计算机名	of_GetComputerName()
Function boolean GetComputerNameA(ref string cname,ref long nbuf) Library "kernel32.dll" ALIAS FOR "GetComputerNameA;ANSI"



end prototypes

type variables
PROTECTED: 
//  CreateFile()
CONSTANT Long GENERIC_READ = 2147483648 
CONSTANT Long GENERIC_WRITE= 1073741824
CONSTANT Long OPEN_EXISTING =3
CONSTANT Long FILE_SHARE_READ =1
CONSTANT Long FILE_SHARE_WRITE =2

end variables
forward prototypes
public function integer of_getcreatedatetime (string as_filename, ref datetime adt)
public function integer of_getlastwritedatetime (string as_filename, ref datetime adt)
public function integer of_setlastwritedatetime (string as_filename, datetime adt)
private function integer of_convertfiledatetimetopb (os_filedatetime astr_filetime, ref datetime adt)
private function integer of_convertpbdatetimetofile (datetime adt, ref os_filedatetime astr_filetime)
public function string of_getvolumeserialnumber ()
public function string of_getcomputername ()
public function integer of__setfiletime (string as_filename, datetime adt)
end prototypes

public function integer of_getcreatedatetime (string as_filename, ref datetime adt);// of_GetCreateDatetime( string as_filename, ref datetime)
//	得到文件创建的时间 
long   ll_handle 
os_finddata    lstr_FindData 
 
// Get the file information 
ll_handle = FindFirstFileA(as_FileName, lstr_FindData) 
If ll_handle <= 0 Then Return -1 
FindClose(ll_handle) 
 
// Convert the date and time 
Return of_ConvertFileDatetimeToPB(lstr_FindData.str_CreationTime, adt) 

end function

public function integer of_getlastwritedatetime (string as_filename, ref datetime adt);// of_GetLastwriteDatetime( string as_filename, ref datetime)
//	得到文件最后修改的时间 
long   ll_handle 
os_finddata    lstr_FindData 
 
// Get the file information 
ll_handle = FindFirstFileA(as_FileName, lstr_FindData) 
If ll_handle <= 0 Then Return -1 
FindClose(ll_handle) 
 
// Convert the date and time 
Return of_ConvertFileDatetimeToPB(lstr_FindData.str_LastWriteTime, adt) 

end function

public function integer of_setlastwritedatetime (string as_filename, datetime adt);//  ====================================================================
//  Event/Fun:   of_setlastwritedatetime(string as_filename,datetime adt)  
//  Returns:     integer 1:OK ; <0:error 
//  Description: 修改文件时间
//  --------------------------------------------------------------------
//  Copyright (c) 2018-2025 GuangZhou Software Co.Ltd(TM), All rights reserved.
//  --------------------------------------------------------------------
//  Written in: 2018-9-20
//  Modified in:
//  ====================================================================

ulong ll_hFile 
os_filedatetime los_LastWriteTime, los_empty

of_ConvertPBDatetimeToFile(adt, los_LastWriteTime)
//写方式打开文件 
ll_hFile = CreateFile(as_filename,GENERIC_WRITE,FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0)
//写文件时间
if SetFileTime(ll_hFile,los_empty, los_empty, los_LastWriteTime)=0 then
	CloseHandle(ll_hFile)
	Return -1
end if
CloseHandle(ll_hFile)
Return 1


end function

private function integer of_convertfiledatetimetopb (os_filedatetime astr_filetime, ref datetime adt);//转换文件系统时间为PB时间
//of_convertfiledatetimetopb(os_filedatetime astr_filetime, ref datetime adt)
os_filedatetime  lstr_LocalTime 
os_systemtime    lstr_SystemTime 
 
If Not FileTimeToLocalFileTime(astr_FileTime, lstr_LocalTime) Then Return -1 
If Not FileTimeToSystemTime(lstr_LocalTime, lstr_SystemTime) Then Return -1 
 
adt = datetime(blob(String(lstr_SystemTime.ui_wyear) + "-" + & 
                    String(lstr_SystemTime.ui_WMonth) + "-" + & 
                    String(lstr_SystemTime.ui_WDay) + ' ' + & 
                    String(lstr_SystemTime.ui_wHour) + ":" + & 
                    String(lstr_SystemTime.ui_wMinute) + ":" + & 
                    String(lstr_SystemTime.ui_wSecond) + ":" + & 
                    String(lstr_SystemTime.ui_wMilliseconds) ) ) 
Return 1 

end function

private function integer of_convertpbdatetimetofile (datetime adt, ref os_filedatetime astr_filetime);//转换PB时间为文件系统时间 
os_filedatetime  lstr_LocalTime 
os_systemtime    lstr_SystemTime 
 
lstr_SystemTime.ui_wyear = year(date(adt)) 
lstr_SystemTime.ui_WMonth = Month(date(adt)) 
lstr_SystemTime.ui_WDay = Day(date(adt)) 
 
lstr_SystemTime.ui_wHour = hour(time(adt)) 
lstr_SystemTime.ui_wMinute = Minute(time(adt)) 
lstr_SystemTime.ui_wSecond = Second(time(adt)) 
lstr_SystemTime.ui_wMilliseconds = Long(String(adt, "fff")) 
 
If Not SystemTimeToFileTime(lstr_SystemTime, lstr_LocalTime) Then Return -1 
 
If Not LocalFileTimeToFileTime(lstr_LocalTime, astr_FileTime) Then Return -1 
 
Return 1 

end function

public function string of_getvolumeserialnumber ();//取硬盘逻辑序列号
//of_GetVolumeSerialNumber()
String  ls_Rootpath ="C:"
String  ls_volumnename =Space(256)//卷名:新加卷
Ulong   lul_VolumeNameSize =256      
Ulong   lul_VolumeSerialNumber
Ulong   lul_MaximumComponentLength =256
Ulong   lul_FileSystemFlags      
String  ls_FileSystemNameBuffer =space(256)//分区格式NTFS      
Ulong   lul_FileSystemNameSize  =256      
boolean lb_rtn      
lb_rtn =GetVolumeInformationA(ls_Rootpath,ls_volumnename,lul_VolumeNameSize,lul_VolumeSerialNumber,&
  lul_MaximumComponentLength,lul_FileSystemFlags,ls_FileSystemNameBuffer,lul_FileSystemNameSize)      
if lb_rtn then
   Return String(lul_VolumeSerialNumber)     
else      
   Return ""     
end if      
         


end function

public function string of_getcomputername ();//  取计算机名 of_GetComputerName()
long   ll_buf=256
String ls_ComputerName
ls_ComputerName = Space(ll_buf)
GetComputerNameA(ls_ComputerName,ll_buf)

Return ls_ComputerName

end function

public function integer of__setfiletime (string as_filename, datetime adt);//  ====================================================================
//  Event/Fun:   of__setfiletime(string as_filename,datetime adt)  
//  Returns:     integer 1:OK ; <0:error 
//  Description: 测试修改文件时间
//  --------------------------------------------------------------------
//  Copyright (c) 2018-2025 GuangZhou Software Co.Ltd(TM), All rights reserved.
//  --------------------------------------------------------------------
//  Written in: 2018-9-20
//  Modified in:
//  ====================================================================

ulong ll_hFile 
os_filedatetime los_CreationTime,los_LastAccessTime,los_LastWriteTime, los_null
datetime ldt_CreationTime,ldt_LastAccessTime,ldt_LastWriteTime

//读方式打开文件 
ll_hFile = CreateFile(as_filename,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0)
//取文件时间
if GetFileTime(ll_hFile,los_CreationTime,los_LastAccessTime,los_LastWriteTime)=0 then
	CloseHandle(ll_hFile)
	Return -1
end if
CloseHandle(ll_hFile)

of_convertfiledatetimetopb(los_CreationTime, ldt_CreationTime)
of_convertfiledatetimetopb(los_LastAccessTime, ldt_LastAccessTime)
of_convertfiledatetimetopb(los_LastWriteTime, ldt_LastWriteTime)
MessageBox(as_filename,string(ldt_CreationTime,"yyyy-mm-dd hh:mm:ss fff")+"~r~n"+string(ldt_LastAccessTime,"yyyy-mm-dd hh:mm:ss fff")+"~r~n"+string(ldt_LastWriteTime,"yyyy-mm-dd hh:mm:ss fff"))
 
of_ConvertPBDatetimeToFile(adt, los_LastWriteTime)
//写方式打开文件 
ll_hFile = CreateFile(as_filename,GENERIC_WRITE,FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0)
//写文件时间
if SetFileTime(ll_hFile,los_null, los_null, los_LastWriteTime)=0 then
	CloseHandle(ll_hFile)
	Return -2
end if
CloseHandle(ll_hFile)
Return 1


end function

on n_cst_filetime.create
call super::create
TriggerEvent( this, "constructor" )
end on

on n_cst_filetime.destroy
TriggerEvent( this, "destructor" )
call super::destroy
end on

event constructor;//  ====================================================================
//  n_cst_filetime    
//  Description: Library "kernel32.dll"
//  取文件建立时间 of_GetCreateDatetime( string as_filename, ref datetime)
//  取文件修改时间 of_GetLastwriteDatetime( string as_filename, ref datetime)
//  设文件修改时间 of_setlastwritedatetime( string as_filename, ref datetime)
//  取硬盘序列号 of_getvolumeSerialNumber()
//  取计算机名	  of_GetComputerName()
//  --------------------------------------------------------------------
//	 Version 12.5
//  --------------------------------------------------------------------
//  Copyright (c) 2018-2025 GuangZhou Co.Ltd(TM), All rights reserved.
//  --------------------------------------------------------------------
//  Written in: 2018-9-20 By Q1852181773
//  Modified in:
//  ====================================================================

end event

 文件下载的示例代码(PB12.5)

//根据文件日期下载

Long     ll_id,ll_filebytes
String   ls_filename,ls_uptime,ls_lastwritetime
blob     lblb_filedata
Integer  li_FileNum
DateTime       ldt_lastwrite
n_cst_filetime lnv_filetime

DECLARE cur_file CURSOR FOR 
	Select Id, FileName, CONVERT(char(16),UpTime,120) ,FileBytes
		From T_appdata Where app=:is_app or app is null  USING SQLCA;
OPEN  cur_file;
do 

FETCH cur_file into :ll_id, :ls_filename, :ls_uptime, :ll_FileBytes ;
IF	SQLCA.SQLCode = 0 THEN	
	If FileExists( ls_filename ) Then
		lnv_filetime.of_getlastwritedatetime( ls_filename, ldt_lastwrite) //取文件修改日期
		ls_lastwritetime = string( ldt_lastwrite,"yyyy-mm-dd hh:mm")
	Else
		ls_lastwritetime = "1900-01-01 00:00"
	End If
		
	If ls_lastwritetime < ls_uptime THEN
		SELECTBLOB FileData INTO :lblb_filedata From T_appdata where Id=:ll_id USING SQLCA ;
		if SQLCA.SQLCode = 0 then
			if Len(lblb_filedata) = ll_FileBytes then
			w_showmsg.Visible = true
			w_showmsg.st_1.text="正在更新文件:"+ls_filename+"~r~n"+w_showmsg.st_1.text
			li_FileNum = FileOpen( ls_filename, StreamMode!, Write!, LockReadWrite!, Replace! )
			FileWriteEx ( li_FileNum, lblb_filedata )
			FileClose ( li_FileNum )
			SetProfileString(FILEINI,is_app,ls_filename,ls_uptime )
			ldt_lastwrite = DateTime(ls_uptime)
			lnv_filetime.of_setlastwritedatetime(ls_filename,ldt_lastwrite)//修改文件时间
		   end if
		end if
   End If
END IF

loop while SQLCA.SQLCode = 0
CLOSE cur_file;
	


 

 

C/S程序自动升级是一个很重要的功能,原理其实很简单,一般包含两个程序一个是主程序,也就是除了升级功能以外的程序 主要包括以下几点:   1 比较版本  2下载文件  3更新文件 4启动主程序。但其中的需要注意的细节很多。      一般服务端会有一个配置文件包含最新更新的文件信息的配置文件,当然这些更新信息也可以存到数据库,或者其他地方。客户端(也就是需要更新的那部分程序)也有一个配置文件包含客户端版本信息,这些信息可以存到专门的一个配置文件中,或者是config文件中,没有一定的规定,可以根据实际设计。    在客户端程序启动时,先启动更新程序通过比较本地版本和服务端最新的版本信息判断是否有新版本,如果有可以直接下载,下载完成替换成功后并更新客户端版本信息,启动主程序。             缺点:如果更新速度由于更新的文件很大或者网速很慢,用户不得不等待很长时间,直到下载完成或者下载失败。             优点:处理完成后,启动的直接就是更新后的程序。不会出现由于主程序在运行导致替换文件时提示文件在使用,不能替换之类的错误。    另一种方法是, 在客户端段程序启动时,启动更新程序,但更新程序不做版本判断,到客户端更新目录下检查有没有下载的新版本,如果有就更新主程序并更新客户端版本信息,然后启动主程序,如果没有就直接启动主程序。由主程序判断是否有新版本,并在后台下载把文件放到客户端更新目录中,下载完成后,提示用户退出主程序,重新启动,在启动时由更新程序并更新客户端客户端版本信息。                 缺点:由于下载是在主程序的后台运行,可能会影响主程序的处理速度。             优点:避免了由于下载导致用户长时间的等待。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值