| 添加到收藏夹 | 返回目录页 | 上一篇:将小写数字金额转成大写金额 |
用DELPHI为ASP开发文件上载组件
asp(active server page)是微软公司的产品,由于它编程很容易上手,能快速开发功能强大的动态网站,现在很多网站(特别是intranet/extranet内部网)采用了nt+iis+asp的模式,使得asp成为目前较为流行的网站开发脚本语言。在web服务中,文件上载服务是一个很常见的功能,而win9x下的pws没有提供相关组件;nt下的iis提供了一个post acceptor组件,但由于它要检查用户的www访问权限而变得不太好用;也可以从internet上下载有关组件,但这些大多都是商业组件,用于下载的是试用版,在使用时间或功能上都有限制。由于asp可以调用标准的ole/com组件,我们可以用vb/vc/delphi等高级编程工具根据我们自己的要求来定制自己的asp文件上载组件,满足自己的应用系统要求。下面将讨论用delphi为asp开发文件上载组件的原理和具体实现过程。
一、文件上载的实现原理
基于web方式数据上传,要遵从rfc1867标准,上载的文件数据也不例外。如用下面html页面文件(delphiup.htm)选择上载文件:
<!-- delphiup.htm:文件上载界面 -->
<html><head><title>文件上载</title></head><body>
用delphi编写的文件上载组件实现文件上载
<form name="uploadform" action="delphiup.asp" method="post" enctype="multipart/form-data">
<p>文件另存为:<input type=text name="saveas">
<p>请要选择上载的文件:<input type=file name="filedata">
<input type="submit" name="b1" value="确认上载"> </p>
</form>
</body></html>
当客户端选择了一个文件(如test.txt,其内容为“这里是一个用于上载的文件的内容。”)并按
“确认上载”按钮提交数据后,服务器端程序收到的数据将具有如下形式:
-----------------------------7cf1d6c47c#13#10
content-disposition: form-data; name="saveas"#13#10#13#10
newfilename#13#10
-----------------------------7cf1d6c47c#13#10
content-disposition: form-data; name="filedata"; filename="d: est.txt"
content-type: text/plain#13#10#13#10
这里是一个用于上载的文件的内容。#13#10
-----------------------------7cf1d6c47c#13#10
content-disposition: form-data; name="b1"#13#10#13#10
确认上载#13#10
-----------------------------7cf1d6c47c--
其中,“-----------------------------7cf1d6c47c”是分界符,用于分隔表单(form)中的各个域;
#13#10是回车换行符的delphi表示。我们可以这样认为,每个表单域的信息描述,都是以分界符加一对回车换行符#13#10开始;表单域名以“name="”开始,以“"”为结束;表单域值以两对回车换行符#13#10#13#10开始,以一对回车换行符#13#10#加分界符结束;文件名称以“filename="”开始,以“"”为结束。有了这些标志,我们就可以获取表单域的名称和值以及要上载的文件的名称,从而实现文件数据的读取和存储了。
二、文件上载的实现过程
在理解上面提到的数据格式后,自己动手编写一个文件上载组件对我们来说已经不是困难了。
(一)开始建立一个asp组件的工程
如果您对用delphi开发ole automation server的步骤不太熟悉的话,请参见《电子与电脑》1999年第06期的一篇文章《用delphi开发用于asp的ole automation server 》。
这里只简要介绍一下操作步骤。
1、建立activex library工程
在delphi中选择菜单file=》new...,在“new item”对话框的activex选项卡中选择“activex library”,delphi会自动创建一个dll工程project1。
2、建立automation组件
在delphi中选择菜单file=》new...,在“new item”对话框的activex选项卡中选择“automation object”;然后在“automation object wizard”对话框中输入class name(如“uploadfile”),instancing选择“multiple instance”即可,单击“ok”后delphi会自动创建一个tlb(type library)文件project1_tlb.pas和一个pas(unit)文件unit1.pas。在type library设计窗口中,将project1改名为myupload,则该文件上载组件的ole注册码为“myupload.uploadfile”。
3、引入asp类型库
为了使用asp的五个内建对象(request、response、server、application、session),需要引入asp类型库。我们主要利用request对象读取从客户端传递到服务器端的数据。
在project菜单中选择“import type library”,在“import type library”对话框的“type libraries”列表选择“microsoft active server pages object library(version 2.0)”(如果没有这个选项,请确定您的计算机上安装了iis3以上或pws4以上并且asp.dll已正确注册),delphi会自动创建一个tlb文件asptypelibrary_tlb.pas,其中有我们需要的asp对象类型声明。
4、定义onstartpage、onendpage过程
当在asp页面上用server.createobject创建一个ole对象实例时,web服务器会调用其方法onstartpage,将asp应用环境信息传递给该对象,我们可以在该过程中获取客户端信息;当在asp页面中释放一个ole对象实例时,web服务器会调用其方法onendpage,我们可以在该过程中进行释放内存等结束操作。在我们这个组件中,我们要用到其onstartpage方法。
onstartpage方法应该在unit1.pas中定义,onstartpage的函数原型为:
procedure onstartpage(ascriptingcontext: iunknown);
其中参数ascriptingcontext是一个iscriptingcontext类型变量,包含五个属性(request、response、server、application、session)分别对应asp的五个内建同名对象。
我们需要在tlb定义窗口(view=》type library)中,为iuploadfile增加方法onstartpage,其declaration语句为“procedure onstartpage(ascriptingcontext: iunknown);”。
(二)提取客户端上传的数据
该工作可以放在onstartpage过程中进行。
利用ascriptingcontext的属性request(类型为irequest)中的属性totalbytes(请求信息内容长度)和方法binaryread可将客户端上传的请求信息数据读取到一个byte类型的数组中,然后按rfc1867标准定义的数据格式来分析和提取数据。
1、首先定义tuploadfile的几个私有变量
在单元文件up01.pas(由unit1.pas另存)中加入对asptypelibrary_tlb.pas的引用(uses),
然后加入
private
fcontentlength : longint;//请求信息内容长度
fcontentdata : variant;//内容数据,以数组形式存储请求信息内容
ffilename, //要上载的文件名称
fdelimeter : string; //表单域分界符
fscriptingcontext : iscriptingcontext;//asp处理上下文环境内容
ffiledatastart, //文件数据开始位置
ffiledataend : longint; //文件数据结束位置
2、提取客户端上传的请求信息数据
//在onstartpage事件中,获取asp上下文信息、请求信息内容、表单域的分界符、文件数据
procedure tuploadfile.onstartpage(ascriptingcontext: iunknown);
var
arequest : irequest; //www请求对象
aolevariant : olevariant; //记录请求信息内容长度
intdelimterlength : integer;//分界符长度
longindex,alongint,longpos : longint;
contentdata : ansistring;//请求信息内容的字符串表示
strtemp : string;
findendoffiledata : boolean;//是否找到文件数据结束位置
begin
//提取客户端上传的请求信息数据
fscriptingcontext := ascriptingcontext as iscriptingcontext;//获取asp上下文信息
arequest := fscriptingcontext.request;//获取www请求信息
fcontentlength := arequest.totalbytes;//请求信息内容长度
//创建动态数组,用于以数组形式存储请求信息内容
fcontentdata := vararraycreate( [0,fcontentlength], varbyte );
//将请求信息内容存储到数组中
aolevariant := fcontentlength;
fcontentdata := arequest.binaryread( aolevariant );//读取请求信息内容
//将请求信息内容转化为字符串,便于定位
contentdata := ;
for longindex := 0 to fcontentlength - 1 do
begin
contentdata := contentdata + chr( byte( fcontentdata[ longindex ] ));
if fcontentdata[ longindex ] = 0 then break;//0表示内容结束
end;
3、获取分界符、上载文件名称
//获取表单域的分界符
longpos := pos( #13#10,contentdata );//回车换行符所在位置
fdelimeter := copy( contentdata,1,longpos-1);//该位置之前的内容为分隔符
//获取带源路径的文件名称,在请求信息内容中,文件名称以
//filename="path/filename"的形式存储
strtemp := filename=";//文件名称在“filename="”之后
longpos := pos( strtemp, contentdata );//获取“filename="”位置
if longpos <= 0 then
begin
ffilename := ;
ffiledatastart := -1;
ffiledataend := -2;
exit;
end;
//获取下个双引号“"”之前的内容,即带源路径的文件名称
longpos := longpos + length( strtemp );
strtemp := ;
for longindex := longpos to fcontentlength - 1 do
if contentdata[ longindex ] <> " then
strtemp := strtemp + contentdata[ longindex ]
else break;
ffilename := strtemp;
4、获取文件数据的在请求信息内容中的开始、结束位置
//文件数据开始位置在文件名称后的第一个#13#10#13#10之后
delete( contentdata, 1, longindex );
strtemp := #13#10#13#10;
ffiledatastart := longindex + pos(strtemp, contentdata) + length(strtemp) - 1;
//文件数据结束位置在下一个#13#10和分界符之前
//由于文件数据可能包含非法字符,不能再用字符串定位函数pos
//查找下一个分界符的位置
ffiledataend := ffiledatastart;
intdelimterlength := length( fdelimeter );
findendoffiledata := false;
while ffiledataend <= fcontentlength - intdelimterlength do
begin
findendoffiledata := true;
for alongint := 0 to intdelimterlength - 1 do
if byte( fdelimeter[ alongint + 1 ] ) <>
fcontentdata[ ffiledataend + alongint ] then
begin
findendoffiledata := false;
break;
end;
if findendoffiledata then break;
ffiledataend := ffiledataend + 1;
end;
if not findendoffiledata then ffiledataend := ffiledatastart - 1//未找到分界符
else ffiledataend := ffiledataend - 3;//分界符,向前跳过#13#10
end;
(三)向asp程序传递信息
在进行了(二)的操作之后,我们的上载组件可以根据asp程序的要求向其传递数据了。目前可以提供的数据有:客户端源文件名称(ffilename,含路径)、文件大小(ffiledataend-ffiledatastart+1)。
首先应该在tlb设计窗口中声明如下两个方法getfilename和getfilesize。
1、返回客户端源文件名称(含路径)
//返回客户端源文件名称(含路径)
function tuploadfile.getfilename: olevariant;
begin
result := ffilename;//客户端源文件名称(含路径)
end;
2、返回文件大小
//返回文件大小(bytes)
function tuploadfile.getfilesize: olevariant;
begin
result := ffiledataend - ffiledatastart + 1;
end;
(四)保存文件
在进行了(二)的操作之后,我们的上载组件可以根据asp程序的要求保存文件了。首先应该在
tlb设计窗口中声明如下两个方法savefileas和savefile。
1、按指定文件名称保存文件
//按指定的文件名称保存文件,参数filename为指定的文件名称,返回值true表示文件保存成功
function tuploadfile.savefileas(filename: olevariant): olevariant;
var
longindex : longint;
afile : file of byte;//以二进制的形式保存文件
bytedata : byte;
begin
result := true;
try
assign( afile, filename );
rewrite( afile );
for longindex := ffiledatastart to ffiledataend do
begin
bytedata := byte( fcontentdata[ longindex ] );
write( afile, bytedata );
end;
closefile( afile );
except
result := false;
end;
end;
2、按缺省文件名称保存文件
//按缺省文件名称保存文件,将文件以同名文件保存在调用页面所在目录
function tuploadfile.savefile: olevariant;
var
currentfilepath : string;
begin
//获取调用页面所在目录
currentfilepath := fscriptingcontext.request.servervariables[path_translated];
currentfilepath := extractfilepath( currentfilepath );
//保存文件
result := savefileas( currentfilepath + extractfilename( ffilename ));
end;
三、上载组件应用举例
在我们的例子中,delphiup.htm是文件上载界面,delphiup.asp用来执行文件上载操作。
delphiup.asp的代码如下:
<!--delphiup.asp:文件上载处理页面-->
<html><head><title>文件上载</title></head><body>
<% dim upload, filename
set upload = server.createobject("myupload.uploadfile")
filename = upload.getfilename
response.write "<br>正在保存文件《"&filename&"》......"
if upload.savefile then
response.write "<br>文件《"&filename&"》上载成功。"
response.write "<br>文件大小为"&upload.getfilesize&"字节。"
else
response.write "<br>文件《"&filename&"》上载失败。"
end if
set upload=nothing %>
</body></html>
四、几点说明
1、由delphi自动生成的源代码编译的dll文件大小有215k,可以在
asptypelibrary_tlb.pas的interface段中将uses中的单元除activex外全部删除,在
myupload_tlb.pas中删除uses中所有单元,则生成的dll文件大小可减少到61k。
2、以上方法同样适用于cgi程序,不过要用twebrequest对象。
以上程序在pwin98+delphi3.0+pws4.0下调试通过。
↓相关文章:
- · 用Delphi进行OpenGL编程学习心得
- · 开发Web应用程序中Cookie使用的问题
- · 在stringgrid控件中使文字内容在cell中做到上下居中
- · 检测Delphi是否正在运行
- · 一个四舍五入函数
- · 解析IP地址为主机域名。
- · 根据数据库表中记录自动构造一棵结构树的一种高效算法
- · 日历函数单元
- · 在Delphi中如何控制其它应用程序窗口
- · 装扮工具提示条
- · 如何在状态栏中加入图标(或图片),还有动态的时间
- · 利用Delphi编写Windows外壳扩展
- · 利用未公开函数实现Shell操作监视
- · 利用Delphi消息处理建立类似Windows开始菜单
- · Delphi中的图形显示技巧
- · Form产生时的事件次序;
- · Delphi中布尔类型辨析
- · AccesS密码的打击
- · Delphi嵌入式汇编一例
- · 在Delphi中实现任意形状的窗体
- · sql server 2005中的DDL触发器
- · asp.net 2.0下嵌套masterpage页的可视化编辑
- · PHP程序加速探索之缓存输出
- · 用C#代码编写的SN快速输入工具
- · (PHP)模板引擎Smarty介绍
- · 用PHP操纵Oracle的LOB类型的数据
- · C# 2.0中泛型编程初级入门教程
- · asp.net 2.0中加密web.config
- · ADO.NET操纵数据库
- · 关于asp.net c#中对cookie的操作
- · asp.net 2.0里当readonly遇上enableviewstate=false
- · C# 2.0与泛型
- · 让3721也无奈的弹出窗口(代码)
- · 玩透9种网页弹出窗口(精)
- · 网站左右两边浮动广告JS代码
- · 一个IP只提示一次设为首页的代码
- · 常用ASP脚本程序集锦*精(适合初学者)
- · 鼠标自动移动/点击
- · PHP程序加速探索之加速工具软件
- · SQLServer2000数据访问基类
- · 图解MySQL数据库的安装和操作
- · 一些ASP初学者常用的代码
- · ASP经典问答收藏之一
- · 一段防注入的通用脚本
- · 简单的防盗链(代码)
- · PHP窜红:革命尚未成功 Java仍需努力
- · 使用PHP编写基于Web的文件管理系统
- · 理解PHP中的MVC编程之控制器
- · 理解PHP中的MVC编程之MVC框架简介
- · SQL Server Express 数据库自动部署问题及解决
- · 用PHP文件上传的具体思路及实现
- · 回顾与展望PHP 5.0的变化与PHP 6.0展望
- · 一个产生中文累计数的代码片断
- · 在SQL Server 2005中解决死锁
- · 30分钟正则表达式指导
- · 不算不知道 44% 数据库开发者使用MySQL
- · 立即释放.net下的com组件
- · XHTML的目标,规则和细节
- · SQL Server 2005 提供的分页查询支持
- · ASP.NET程序中常用的三十三种代码

