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;