原文网址: http://www.yourblog.org/Data/20061/411359.html
日期:2006年1月15日 星期日 天气:晴朗 作者:ThornBird
通过SQL Server在服务器上存取文件
发表:2006-1-15 15:26:05 出处:你的博客网(yourblog.org)
--------------------------------------------------------------------------------
前些天改公司的程序,发现员工基本资料表中的照片字段竟是字符型,只保存照片的路径。我们的程序一般是用远程桌面访问,或是把程
序所在目录映射为本地盘并运行程序。这样一来,图片只能放在服务器上才能进行显示、打印,且如果采取映射本地盘的方式,每个客户端应
该都必须映射为相同的本地盘(或者把照片放在程序所在目录下,保存相对路径)。于是我把照片字段改成text类型,把文件存储到数据库中
,不过一个同事不同意我的做法,于是只好作罢。但后来我想到其实可以把照片“上传”到服务器上,需要使用时再“下载”到本地,然后数
据库中保存文件在服务器上的实际路径。通过查资料,我知道了可以用 sp_makewebtask 存储过程把查询结果保存到服务器上,遗憾的是它是
保存为网页的格式,而不能把文件照原样保存到服务器上。不过无所谓了,只要“下载”时再对文件结构进行分析就可以了,这样一来就可以
实现“上传”的功能了。至于“下载”,可以用 BULK INSERT 语句来实现。
我的思路是这样的:把文件进行编码后保存到 SQL Server 的临时表中,然后执行 sp_makewebtask 存储过程保存文件;使用“上传”的
文件时则可以用 BULK INSERT 语句把文件存入临时表中,然后再通过查询得到文件的全部内容,然后进行分析和解码后进行保存。上面两个步
骤都需要有足够的权限。这就是我的 ServerFileAccess 类的基本思路,这个类主要有下面几个方法:
SetConnectString 设置连接字符串
SetConnectHandle 设置连接句柄
Connect 与 SQL Server 建立连接
Disconnect 断掉连接
UploadFile 把客户端的文件“上传”到服务器上
GetFileFromServer 获取服务器上的文件
GetUploadFileFromServer 获取之前“上传”到服务器上的文件
DownloadFile “下载”服务器上的指定文件到本地
DownloadUploadFile “下载”之前“上传”到服务器上的文件到本地
下面是 ServerFileAccess 类的代码及演示:
ServerFileAccess.prg
DEFINE CLASS ServerFileAccess AS Custom
PROTECTED ConnectString
PROTECTED ConnectHandle
PROTECTED Connected
PROTECTED FLAG_START
PROTECTED FLAG_END
PROTECTED ROWTERMINATOR
PROCEDURE Init
THIS.ConnectString = ""
THIS.ConnectHandle = -1
THIS.Connected = .F.
THIS.FLAG_START = "<<START>>"
THIS.FLAG_END = "<<END>>"
THIS.ROWTERMINATOR = CHR(13)
ENDPROC
PROCEDURE Destroy
IF THIS.Connected = .T.
THIS.Disconnect()
ENDIF
ENDPROC
PROCEDURE SetConnectString
LPARAMETERS cServer, cDatabase, cUserId, cPassword
THIS.ConnectString = "Driver=SQL Server;" + ;
"Server=" + cServer + ";" + ;
"Database=" + cDatabase + ";" + ;
"Uid=" + cUserId + ";" + ;
"Pwd=" + cPassword
ENDPROC
PROCEDURE SetConnectHandle
LPARAMETERS nConnectHandle
THIS.ConnectHandle = nConnectHandle
ENDPROC
PROCEDURE Connect
PRIVATE nDispLogin
nDispLogin = SQLGETPROP(0, "DispLogin")
= SQLSETPROP(0, "DispLogin", 3)
IF THIS.ConnectHandle > 0
RETURN .T.
ENDIF
THIS.ConnectHandle = SQLSTRINGCONNECT(THIS.ConnectString)
= SQLSETPROP(0, "DispLogin", nDispLogin)
IF THIS.ConnectHandle > 0
THIS.Connected = .T.
RETURN .T.
ENDIF
RETURN .F.
ENDPROC
PROCEDURE Disconnect
PRIVATE lReturnValue
lReturnValue = .T.
THIS.ConnectString = ""
TRY
= SQLDISCONNECT(THIS.ConnectHandle)
CATCH
lReturnValue = .F.
ENDTRY
THIS.ConnectHandle = -1
Connected = .F.
RETURN lReturnValue
ENDPROC
PROCEDURE UploadFile
LPARAMETERS cClientFile, cServerFile
PRIVATE lReturnValue, nReturnValue, cTableName, cSQL, cDrop,
cFileData, cRandKey
lReturnValue = .F.
nReturnValue = -1
cTableName = "##" + SYS(2015)
cSQL = [CREATE TABLE ] + ;
cTableName + ;
[ (RandKey char(8) NULL, FileData text NULL)]
cDrop = [DROP TABLE ] + cTableName
cFileData = THIS.FLAG_START + ;
STRCONV(FILETOSTR(cClientFile), 15) + ;
THIS.FLAG_END
cRandKey = SYS(3)
= SQLEXEC(THIS.ConnectHandle, cSQL)
cSQL = [INSERT INTO ] + cTableName + ;
[ (RandKey, FileData)] + ;
[ VALUES] + ;
[ (’] + cRandKey + [’, ’] + cFileData + [’)]
nReturnValue = SQLEXEC(THIS.ConnectHandle, cSQL)
IF nReturnValue < 0
= SQLEXEC(THIS.ConnectHandle, cDrop)
RETURN lReturnValue
ENDIF
cSQL = [EXECUTE master..sp_makewebtask ] + ;
["] + cServerFile + [", ] + ;
["SELECT FileData FROM ] + cTableName + ;
[ WHERE RandKey = ’] + cRandKey + [’"]
nReturnValue = SQLEXEC(THIS.ConnectHandle, cSQL)
IF nReturnValue > 0
lReturnValue = .T.
ENDIF
= SQLEXEC(THIS.ConnectHandle, cDrop)
RETURN lReturnValue
ENDPROC
PROCEDURE GetFileFromServer
LPARAMETERS cServerFile
PRIVATE cFileData, nReturnValue, cTableName, cSQL, cDrop, ;
cCurrentAlias, cAlias, i
cFileData = ""
nReturnValue = -1
cTableName = "##" + SYS(2015)
cSQL = [CREATE TABLE ] + ;
cTableName + ;
[ (FileData text NULL)]
cDrop = [DROP TABLE ] + cTableName
nReturnValue = SQLEXEC(THIS.ConnectHandle, cSQL)
IF nReturnValue < 0
RETURN cFileData
ENDIF
cSQL = [BULK INSERT ] + cTableName + ;
[ FROM ’] + cServerFile + [’] + ;
[ WITH (ROWTERMINATOR = ’] + ;
THIS.ROWTERMINATOR + [’)]
nReturnValue = SQLEXEC(THIS.ConnectHandle, cSQL)
IF nReturnValue < 0
= SQLEXEC(THIS.ConnectHandle, cDrop)
RETURN cFileData
ENDIF
cCurrentAlias = ALIAS()
cAlias = SYS(2015)
cSQL = [SELECT FileData FROM ] + cTableName
nReturnValue = SQLEXEC(THIS.ConnectHandle, cSQL, cAlias)
= SQLEXEC(THIS.ConnectHandle, cDrop)
IF nReturnValue < 0
RETURN cFileData
ENDIF
SELECT (cAlias)
GO TOP
SCAN
cFileData = cFileData + ;
IIF(ISNULL(FileData) = .T., "", ALLTRIM(FileData)) + ;
IIF(RECNO() = RECCOUNT(), "", THIS.ROWTERMINATOR)
ENDSCAN
USE IN (cAlias)
IF EMPTY(cCurrentAlias) = .F.
SELECT (cCurrentAlias)
ENDIF
RETURN cFileData
ENDPROC
PROCEDURE GetUploadFileFromServer
LPARAMETERS cServerFile
PRIVATE cFileData, nStart, nLength
cFileData = ""
cFileData = THIS.GetFileFromServer(cServerFile)
IF EMPTY(cFileData) = .T.
RETURN cFileData
ENDIF
nStart = AT(THIS.FLAG_START, cFileData) + LEN(THIS.FLAG_START)
nLength = AT(THIS.FLAG_END, cFileData) - nStart
cFileData = SUBSTR(cFileData, nStart, nLength)
cFileData = STRCONV(cFileData, 16)
RETURN cFileData
ENDPROC
PROCEDURE DownloadFile
LPARAMETERS cServerFile, cClientFile
PRIVATE cFileData
cFileData = THIS.GetFileFromServer(cServerFile)
= STRTOFILE(cFileData, cClientFile)
RETURN .T.
ENDPROC
PROCEDURE DownloadUploadFile
LPARAMETERS cServerFile, cClientFile
PRIVATE cFileData
cFileData = THIS.GetUploadFileFromServer(cServerFile)
= STRTOFILE(cFileData, cClientFile)
RETURN .T.
ENDPROC
ENDDEFINE
ServerFileAccess_Demo.prg
SET PROCEDURE TO ServerFileAccess.prg
oServerFileAccess = CREATEOBJECT("ServerFileAccess")
oServerFileAccess.SetConnectString("127.0.0.1", "master", "sa", "123456")
oServerFileAccess.Connect()
*-- 演示 UploadFile 方法
cSource = GETFILE("", "上传文件(&F):", "选择", 0, "请选择要上传到服务器上的文件")
cTarget = ALLTRIM(INPUTBOX("保存路径(含文件名):", "请输入上传路径及目标文件名"))
? oServerFileAccess.UploadFile(cSource, cTarget)
*-- 演示 DownloadUploadFile 方法
cFileName = PUTFILE("保存文件(&F)", "", JUSTEXT(cSource))
? oServerFileAccess.DownloadUploadFile(cTarget, cFileName)
oServerFileAccess.Disconnect()