用DELPHI为ASP开发文件上载组件 (转)[@more@]
用
Delphi 为
ASP 开发
文件 上载
组件 深圳王发军 返回
ASP(Active Server Page)是
微软 公司的产品,由于它
编程 很容易上手,能
快速 开发功能强大的动态网站,现在很多网站(特别是Intr
.NET /Extranet内部网)采用了NT+IIS+ASP的
模式 ,使得ASP成为目前较为流行的网站开发脚本语言。在WEB服务中,文件上载服务是一个很常见的功能,而WIN9X下的PWS没有提供相关组件;NT下的IIS提供了一个Post Acceptor组件,但由于它要检查
用户 的WWW访问
权限 而变得不太好用;也可以从Internet上
下载 有关组件,但这些大多都是商业组件,用于下载的是试用版,在使用时间或功能上都有限制。由于ASP可以
调用 标准的OLE/COM组件,我们可以用VB/VC/DELPHI等高级编程工具根据我们自己的要求来定制自己的ASP文件上载组件,满足自己的应用
系统 要求。
下面将讨论用DELPHI为ASP开发文件上载组件的原理和具体实现过程。
一、文件上载的实现原理
基于
web 方式数据
上传 ,要遵从
rfc 1867标准,上载的文件数据也不例外。如用下面HTML页面文件(delphiup.htm)选择上载文件:
<!-- DelphiUp.htm:文件上载界面 -->
文件上载 用DELPHI编写的文件上载组件实现文件上载
RM NAME="UPLOAD Form" ACTION="delphiup.asp" METHOD="POST" ENCTYPE="multipart/form-data">文件另存为:
请要选择上载的文件:
当客户端选择了一个文件(如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:文件上载处理页面-->文件上载 <% dim Upload, FileName set Upload = Server.CreateObject("MyUpload.UploadFile") FileName = Upload.GetFileName Response.Write " 正在保存文件《"&FileName&"》......" if Upload.SaveFile then Response.Write " 文件《"&FileName&"》上载成功。" Response.Write " 文件大小为"&Upload.GetFileSize&"字节。" else Response.Write " 文件《"&FileName&"》上载失败。" end if set Upload=nothing %> 四、几点说明 1、由DELPHI自动生成的源代码 编译的DLL文件大小有215K,可以在 ASPTypeLibrary_TLB.PAS的Interface段中将Uses中的单元除ActiveX外全部删除,在 MyUpload_TLB.PAS中删除Uses中所有单元,则生成的DLL文件大小可减少到61K。 2、以上方法同样适用于CGI程序,不过要用TWebRequest对象。 以上程序在Pwin98 +Delphi3.0+PWS4.0下调试 通过。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/10790663/viewspace-954392/
,如需转载,请注明出处,否则将追究法律责任。