大侠们,一个关于压缩、打包、上下传FTP的问题

zhaoshaom 2004-09-18 11:29:50
我作一个的商业管理系统,现在要把各分店全部连起来,现在使用的是FTP,我的办法是:
把夺DBF汇总成地一个的压缩文件,然后传上去网站上,现在问各路大侠,用VFP如何使用FTP把数据传上去?
(1)如何压缩文件,(2)如何打包文件,(3)如何上下传文件
...全文
238 4 打赏 收藏 举报
写回复
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
Hewiit 2004-09-21
  • 打赏
  • 举报
回复
(1)如何压缩文件,(2)如何打包文件:用压缩控件
(3)如何上下传文件:有FTP控件
建议到网上搜索一下
十豆三 2004-09-18
  • 打赏
  • 举报
回复
我还不了解 Web Service 怎么办?

如果,您不了解怎么编写 Web Service 服务端程序,请查看 BOE 的《用Visual FoxPro编写Web Service》;

如果,您不了解怎么编写 Web Service 客户端程序,请查看 BOE 的《Visual FoxPro 7 全新登场-- Web Service Client》;

下载的示例怎么使用

与往常一样,基本上编译、发布以后就可以使用了。要注意的就是每一个 prg 文件里都有预定义变量,一般是路径指向,根据你那里情况改变它们就行了!

Web Service 到底有什么用?

如果大家亲身感受过 Web Service,您就会发现调用 Internet 上的 Web Service 就像调用本机的函数那么简单。通过 Web Service,我们可以交互各种数据,包括文件!

也许今天 Foxer 对 Web Service 的疑惑,就像当年对 SQL Server 的疑惑那样。做个有心人吧,也许你永远不会使用这个技术,也许明天你就要使用这门技术,了解它总是好的,这是我的观点!

有网友说我不务实,老是弄一些虚的东西,反正也没几个人看得懂,蒙人罢了。也不知道说的是对、是错,更不知道是从那里抄来的……这种恶意中伤,不知道这些人是什么心态,对此我只想说:兄弟,请给我一片宁静的天空!!!

好了,就到这里!下次再见!

更多话题

今天是 2002年7月20日。一个星期前,我推出了本文,得到了一些朋友的相应。他们提出了一些问题,我希望通过续写此文一并作答。

实现文件上传

朋友们问我,你的示例代码里只有文件从服务器下载到客户端的介绍,是不是在暗示 Web Service 不能实现文件从客户机上传到服务器?不是,这是我的疏忽,本来应该提到 “文件上传” 的问题!

其实这里所谓 “文件上传” 是很简单的,只不过是 “文件下载” 的逆向思维!客户端把文件读起,并转换成为 Base64 编码的 XML 字符串,作为调用服务器有关接口函数的参数;服务器只要把客户端送过来的XML字符串解码保存成为文件即可!

服务器端代码

FUNCTION SaveFile(sUser as String,sPassWord as String,sFileName as String,sXml as String) as Boolean
IF sUser<>"Admin" OR sPassWord<>"PassWord" then
RETURN .f.
ENDIF

IF STRTOFILE(STRCONV(sXml,14),DataBasePath+sFileName)>0 then
RETURN .t.
ELSE
RETURN .f.
ENDIF
ENDFUNC

这里的核心代码就是:STRTOFILE(STRCONV(sXml,14),DataBasePath+sFileName) 。它的作用就是:对参数 sXml 进行 Base64 解码,并把解码后的数据保存为文件。

另外,一些网友提到了是不是用户验证的问题,这里我用了最简化的代码解释一下:

IF sUser<>"Admin" OR sPassWord<>"PassWord" then
RETURN .f.
ENDIF

这里要求用户名(sUser)为“Admin”,口令(sPassWord)为"PassWord" 时,才可以使用本接口函数。不然函数直接返回,而不往下面继续执行!

大家想象一下,这段简单的代码其实可以扩充成为复杂的 “用户、权限” 系统,这只是普通的程序设计概念,这里就不多说了!

客户端的代码

完整代码,详见 SaveFile.prg

#define TempPath "J:\webs\ClientData\"
LOCAL mywebs as FoxWebService
LOCAL loWS
loWS = NEWOBJECT("Wsclient",HOME()+"ffc\_webservices.vcx")
loWS.cWSName = "FoxWebService"
mywebs = loWS.SetupClient("http://BOEWORKS/FoxWebS/FoxWebService.WSDL", "FoxWebService", "FoxWebServiceSoapPort")
IF mywebs.SaveFile("Admin","PassWord","pic.jpg",STRCONV(FILETOSTR(TempPath+"yl_22_28.JPG"),13))
MESSAGEBOX("成功!")
ELSE
MESSAGEBOX("失败!")
ENDIF

客户端的代码更是简单,核心就是:mywebs.SaveFile("Admin","PassWord","pic.jpg",STRCONV(FILETOSTR(TempPath+"yl_22_28.JPG"),13))。其作用是读取 JPG 文件 yl_22_28.jpg,并对它进行 Base64 编码,最后作为 SaveFile 接口函数的 sXml 参数送往服务器!

就这个应用来说,我的想法是把2002年7月22日到7月28日的“日历”替换原先的日历文件!

Web Service 传送文件与 FTP 的简单比较

Web Service 采用的 Http 协议的 “客户端请求、服务器端响应” 的模式,属于同步机制!也就是说客户端调用服务器接口函数以后,就等待,直到服务器给出结果(或者超时)!这种模式的好处在于:客户机、服务器交互时就像我们在Visual FoxPro 里调用内部函数那样—等待返回结果,这给编程带来了极大地方便!个人感受,用 FTP 控件,交互性没有 Web Service 好!

大家注意一下,我们用 Visual FoxPro 编写 Web Service 时,可以编写很多逻辑代码。换言之,用 Web Service 传送文件时,服务器更客户化,无论是上传、下载文件,我们的服务器都可以完成复杂的客户化的逻辑代码!当然,如果你有兴趣编写 FTP Server 的话,一样可以做到!

说着这么多,归根到底一句话:Web Service 不是为了传送文件而设计的,FTP 天生就是传文件的!可能有人要揍我了,我们辛苦看了2个星期的文章,换回的是一句:Web Service 不是为了传送文件而设计的。

这一点大家一定要注意:Web Service 传文件是此技术的一项副产品,而不是设计时的出发点!Web Service的函数调用模式,特别适合商业逻辑的实现。FTP 是文件传输协议,被广泛使用,自然有它的优势,例如两进制文件直接传递、断点续传等!

所以,我们在平时应用中,如果文件体积不大,并且传送文件的需求集合在 Web Service 应用里的,就应该使用这里我们介绍的方法:用 Web Service 传送文件!如果只是一个孤立文件传送任务或者被传送的文件很大,就应该采用 FTP 或者是 Email 方式!

所谓文件的大小不是一个定数。我个人的意见是关键看传送的时间,如果一个1M的文件,要传送10分钟,我想对这种环境来讲 1M 就是一个大文件了;反过来,如果一个 5M 的文件,只要用 30 秒就能传递完成了,那么在这种环境下它只是一个小文件!

进一步,这个等待时间的长短,是要您自己决定了!

异步调用 Web Service

这里就有人问道:我的Web Service提供的接口函数工作时间比较长,能不能实现客户端调用以后,不等待返回结果而继续处理其他任务!

这显然是希望得到一种 “异步处理” 的环境!刚才我已经提到了 Web Service 是以“同步模式”工作的,更明确的说法是:没有异步工作的 Web Service,只有对 Web Service 的异步调用!显然,问题的关键在客户端了!

在 Visual FoxPro 如何实现对 Web Service 的异步调用,我现在还没有头绪!不过在 .net 里倒是可以实现,有两种方法:回调函数和WaitHandle() 函数。前者适合 WinForm,后者适合于 Asp.Net。

十豆三 2004-09-18
  • 打赏
  • 举报
回复
客户端调用

客户端调用这个Web Service 也是很容易的事情:我们使用 GetPicture() 接口取得承载图片的 XML 字符串,并还原它为test.jpg,然后把这个 jpg 文件贴在 Visual FoxPro 的主窗体里!

这里用于解码 base64 并保存文件的代码是:

STRTOFILE(STRCONV(mywebs.GetPicture,14),TempPath+"test.jpg",.t.)

完整代码如下,具体见Getpic.prg:

#define TempPath "J:\webs\ClientTemp\"
LOCAL mywebs as FoxWebService
LOCAL loWS
loWS = NEWOBJECT("Wsclient",HOME()+"ffc\_webservices.vcx")
loWS.cWSName = "FoxWebService"
mywebs = loWS.SetupClient("http://BOEWORKS/FoxWebS/FoxWebService.WSDL", "FoxWebService", "FoxWebServiceSoapPort")
STRTOFILE(STRCONV(mywebs.GetPicture,14),TempPath+"test.jpg",.t.)
_screen.Picture=TempPath+"test.jpg"

传送 DBF 文件

引入 Zip 技术

以上我们解决了用 Web Service 传送文件的问题,其实仔细思考一下,您会发现还有一些细节问题需要有交代:

有的被传送文件(数据)很大,传送起来对网络压力很大,而且耗费时间。怎么使数据变小、缩短传送时间、减轻网络压力呢?

如果一次需要传送多个文件该怎么实现?

我的解决方法是:用 Zip 方式压缩被传送文件。

Zip 对 BMP、TXT、DBF 等类型的文件有很高的压缩率,压缩这些文件能使数据量大大减少,对快速传递非常有利,同时也减少了网络上的数据流量!

Zip 还有一个功能就是可以将多了文件包裹在一个Zip文件里,这样就解决了一次传递多个文件的问题。

另外,Zip 还支持压缩口令,有资料提到用十几位长度的中英文混合的压缩口令,一般很难破解!这里我们压缩时加入口令保护,对文件传输安全应该是有好处的!

很可惜,Visual FoxPro 没有直接提供 Zip 功能,一般我们使用第三方的动态链接库或者是 ActiveX 控件来实现 Zip。这里我使用了名为 ZipToolKit.dll 的动态链接库,是我封装的。功能简单,但用在 Web Service 客户端和服务器端应该是可以胜任的(ZipToolKit.dll 是我为了这篇文章特意编写的,所以我不对 ZipToolKit.dll 提供任何技术支持和担保!)。

ZipToolKit.dll 的用法

压缩文件

函数声明:DECLARE Integer ZipFiles IN "ziptoolkit.dll" String,String,integer,String
返回值:0>=0 被成功压缩文件的数量;-1 失败
参数1:被压缩文件列表。用全路径表示文件;支持通佩符;多个文件用分号分割;参数长度不超过255个字符
参数2:压缩后文件名称。
参数3:压缩级别。取值 1-9,取值越大,压缩比率越高,处理越慢。
参数4:压缩口令。空白字符串表示不设口令。

例如:
DECLARE Integer ZipFiles IN "ziptoolkit.dll" as zip String,String,integer,String
?Zip("F:\zip\abc.bmp;F:\zip\ab.txt","F:\zip\test.zip",9,"")
clear dlls "zip"

解压缩文件

函数声明:DECLARE Integer UnZipFile IN "ziptoolkit.dll" String,String,String
返回值:0>=0成功解压缩文件的数量;-1失败
参数1:被解压缩文件
参数2:释放路径
参数3:解压缩口令。空白字符串表示不设口令。

例如:
DECLARE Integer UnZipFile IN "ziptoolkit.dll" as unzip String,String,String
?unzip("F:\zip\test.zip","F:\zip\t1t\","")
clear dlls "unzip"

为什么这里不用 CursorToXML() 处理 DBF 的传送问题

言归正题,让我们使用 Web Service 传送 DBF 文件。如果您是 BOE 的老读者,也许你会有这样的疑问:DBF 不是可以通过 cursortoxml() 函数直接转为 XML 字符串,为什么要另辟蹊径把 DBF 简单的作为文件、用通用的传送文件的方式处理呢?

我想有两点理由。其一,cursortoxml() 函数不支持通用字段数据的转换,也就是说如果一个 Cursor(DBF) 里有通用字段,这个字段将被 cursortoxml() 忽略,说的再明显一点就是,cursortoxml 不支持通用字段类型!遇到这样的问题,我个人以为直接传送 *.dbf 和*.fpt 文件是最简单的方法!

把 DBF 作为文件传递还有另一个原因,当数据量稍微大一点的时侯,用 cursortoxml() 会产生庞大的 XML 字符串(上千条数据,就可能形成几M的 XML),如果采用 Zip 压缩 DBF,有极好的“瘦身”作用!

当然,我们以前介绍的 cursortoxml() 的做法依然有它的好处,并且它依然是传送数据表的主流方法,这是因为在 Internet 的应用时,我们并不提倡让大量数据在网络上传递,只是传送有用的行和列;同时,一般的商务程序处理通用数据的机会并不多;还有使用 cursortoxml() 函数处理表格数据,是非常简单的。所以千万不要因为今天的话题而 “走火入魔” 了!!!

服务器端的代码

这是一个非常简单的程序:接口函数 GetDBF 返回一个承载着 DBF 文件的 XML 字符串给客户端程序(其实被传送的是 Zip 文件的 Base64 编码)!这里为了简化代码,被返回的表文件是固定的:employee.dbf 和它的附属文件 employee.fpt。

受保护函数 ZipEncode64 能够将指定的文件压缩成为 zip文件,再将zip文件编码成为 Base64:

下面就是这两个函数,具体见prg1.prg文件!

PROTECTED FUNCTION ZipEncode64(sFile as string,iLevel as Integer,sPsd as string) as String
LOCAL sTempZipFile,sBase64 as String
sTempZipFile=TempPath+SYS(2015)
DECLARE Integer ZipFiles IN "ziptoolkit.dll" as zip String,String,integer,String
IF zip(sFile,sTempZipFile,iLevel,sPsd)>0
sBase64=this.Encode64(sTempZipFile)
ELSE
sBase64=""
ENDIF
CLEAR DLLS "ZIP"
IF FILE(sTempZipFile)
DELETE FILE &sTempZipFile
ENDIF
RETURN sBase64
ENDFUNC

FUNCTION GetDbf(iZipLevel as Integer,sPsd as string) as String
RETURN this.ZipEncode64(DataBasePath+"employee.dbf;"+DataBasePath+"employee.fpt",iZipLevel,sPsd)
ENDPROC

客户端调用

客户端调用这个Web Service 也是很容易的事情:我们使用 GetDBF() 接口取得承载 Zip 的 XML 字符串,并还原它为test.zip,然后把这个 zip 文件解压缩到临时目录里,就得到了employee 表文件,最后打开并显示 employee!

完整代码如下,具体见GetDBF.prg:

#define TempPath "J:\webs\ClientTemp\"
#define ToolPath "J:\webs\tools\"
LOCAL mywebs as FoxWebService
LOCAL loWS
loWS = NEWOBJECT("Wsclient",HOME()+"ffc\_webservices.vcx")
loWS.cWSName = "FoxWebService"
mywebs = loWS.SetupClient("http://BOEWORKS/FoxWebS/FoxWebService.WSDL", "FoxWebService", "FoxWebServiceSoapPort")
SET PATH TO ToolPath
IF SELECT("employee")>0
USE IN employee
ENDIF
STRTOFILE(STRCONV(mywebs.GetDbf(9,"BOE 数据网络工作室"),14),TempPath+"test.zip",.t.)
DECLARE Integer UnZipFile IN "ziptoolkit.dll" as unZip String,String,String
IF UnZip(TempPath+"test.zip",TempPath,"BOE 数据网络工作室")>0
USE TempPath+"employee"
BROWSE
ENDIF
CLEAR DLLS "unzip"

并在一起
十豆三 2004-09-18
  • 打赏
  • 举报
回复
用 Web Service 传送文件

在实际开发中传写文件是经常性的需求,Visual FoxPro 程序员要在 Internet 上做这件事情,通常是用电子邮件或者是FTP的方式,那么 Web Service 能不能提供一种新方法呢?

当然可以用 Web Service 传送文件,这就是今天我们讨论的主题。

在开始之前,要感谢 将来是我、漫步者和 BOBY 在有关技术上对我的帮助,将这篇文章献给你们!!!

把文件转化为文本

Base64 编码/解码

我在以前的文章中多次提到 Web Service 是依靠 XML 来描述数据的,延伸到传送文件的问题,可以这么想:只要能用 XML 表示被传送的文件,就可以达到用 Web Service 的目标!

计算机里的各种文件,基本上都是以两进制形式存在的;而我们知道 XML 只是最简单的文本信息。那么怎样实现任意文件与文本的相互转化呢?这显然是问题的关键所在!

我们就不饶圈子了,直接给出解决方案:Base64 编码/解码!Base64 编码/解码 规则是在 RFC2045,Multipurpose Internet Mail Extension (MIME) 里定义的。所谓 编码 就是:把两进制数据转换成 Base64(文本信息);所谓 解码 就是把 Base64 (文本信息) 还原为原始数据!

注意过没有:电子邮件附件也多用 Base64 编码/解码!

Base64 是文本,它用64个可见字符表示信息,这64个可见字符是:a-z,A-Z、0-9、+、/、=。

具体实现 Base64 编码/解码 的算法也不是太困难,由于 Visual FoxPro 7 对 Base64 有具体的支持,所以这里我就不谈论 Base64 的算法了!

就请记住一个结论:XML 只能传“可见文本”,我们对任意文件用 Base64 编码转换为文本,于是就可以用XML就能传送了。传送完毕,只需要把 Base64 解码成为两进制数据,保存为文件就行了!

对了,还有一点要说明的是:根据Base64编码的算法,数据转换为 Base64 以后,一般体积要比原先增加1/3!这也许就是使用 Base64的代价了……

在 Visual FoxPro 里实现 Base64 编码/解码

发现 StrConv() 的秘密

Visual FoxPro 里有函数能解决“Base64 编码/解码”的问题吗?没有,你去查遍帮助都可能找不到!也许我的运气好、也许是我的感觉好,为了这个问题我特意测试了 Visual FoxPro 专门用来编码、解码的函数 STRCONV(cExpression, nConversionSetting ),有趣的是 IntelliSense 揭示了参数 nConversionSetting 的秘密!



nConversionSetting=13 时,实现 Base64 编码功能:把两进制数据转换成 Base64(文本信息)!

nConversionSetting=14 时,实现 Base64 解码功能:把 Base64 (文本信息) 还原为原始数据!

不知道为什么,微软没有把这两个参数编入帮助,起码我的帮助没有提到这两个参数,真是暴敛天物!!!

使用 StrConv() 函数

如果要把 C:\abc.jpg 转化为 Base64 编码,可以这样实现:

local cBase64 as String
cBase64=Strconv(FiletoStr("c:\abc.jpg"),13)

如果要把上述 Base64 编码还原为文件 test.jpg,可以这样实现:

StrtoFile(Strconv(cBase64,14),"c:\test.jpg",.t.)

是不是非常容易?就是一层窗户纸,点破就一点儿也不稀奇了!其实,如果您读过 Boe 以前关于制作 Web Service 的文章,加上今天的这么点技巧,“怎么用 Web Service 传送文件” 对您应该是很容易的事情了!

实现 Web Service

传送一张图片

服务器端的代码

这是一个非常简单的程序:接口函数 GetPicture 返回一个承载着图片的 XML 字符串给客户端程序!这里为了简化代码,被返回的图片也是固定的:pic.jpg。

受保护函数 Encode64 能够将制定的文件编码成为 Base64,核心代码就是:

RETURN STRCONV(FILETOSTR(sFileName),13)

下面就是这两个函数,具体见prg1.prg文件!

PROTECTED FUNCTION Encode64(sFileName as string) as String
IF FILE(sFileName)
RETURN STRCONV(FILETOSTR(sFileName),13)
ELSE
RETURN ""
ENDIF
ENDFUNC

FUNCTION GetPicture as String
RETURN this.Encode64(DataBasePath+"pic.jpg")
ENDPROC
发帖
VFP

2578

社区成员

VFP,是Microsoft公司推出的数据库开发软件,用它来开发数据库,既简单又方便。
社区管理员
  • VFP社区
加入社区
帖子事件
创建了帖子
2004-09-18 11:29
社区公告
暂无公告