| 
                                     摘 要 本文通过delphi的Tihttp控件,将超大文件分割成几个小文件,通过构造的表单数据流, 
                                                直接发送到接收数据网页,由vb编写的服务器端进行文件接收和还原 
                                    一、问题的提出: 
                                    本单位在开发课件生成系统时,需要通过浏览器向服务器指定目录传送大的音、视频文件。在微软asp中未提供相应的控件,asp.net虽然提供了form表单中的file控件进行文件上传,但对上传的文件有长度限制,文件长度大于50M上传会失败,而微软基于安全考量,file控件中的文件名在运行期间只读,这样利用微软提供的控件向服务器端上传长度超过50M的文件变为不可行,必须另劈蹊径。 
                                    二、解决方案 
                                    delphi以其强大的控件集,快速的RAD开发,深得程序开发人员的青睐,其最新控件集Indy,集成了大部分流行的Internet协议,包括TCP、UDP、DNS、ICMP、FINGER、FTP、GOPHER、HTTP、POP3、SMTP、TELNET、WHOIS,而浏览器的传输协议为http。这样我们可以利用delphi7中的TIHTTP控件,将数据打包后上传到服务器端。基本思路为:开发两部分功能程序,一个为ActiveX控件,嵌入到网页中,负责将客户端本地上传文件分解成n个数据包,每个数据包直接编码成“multipart/form-data”格式的表单信息,依次调用TIhttp控件的post方法向服务器端发送信息。另一个为服务器端的com组件,接受发送过来的原始信息,将数据包拼接还原成文件保存到服务器的指定目录中。 
                                    三、技术要点: 
                                        1.Delyhi 7开发Active X控件要点:选择新建项目→Active x标签→Active Form→填入控件名可快速搭建一个Acfire X控件架构,产生一个表单和一个框架代码文件。 
                                    2.上传Active x控件设计要点:①表单控件中放置一个编辑控件、三个命令按钮、一个进度条控件、一个文本标签控件、一个文件对话框控件。编辑控件用来放置上传文件名。一个浏览按钮打开文件选择对话框,选择上传文件;进度条控件显示上传文件进度;文本标签显示上传文件百分比,取消按钮可中断文件上传。 
                                    ②项目包含两个代码文件,其中一个文件用来将上传文件拆分成小数据包。其关键代码如下: 
                                        for y:=0 to filenum  do 
                                           begin 
                                             if y=0  then   //第一个包 
                                                 begin 
                                                if y <> filenum then 
                                                      begin 
                                                          for i:=1 to basenum do 
                                                            begin 
                                                               read(f,ch); 
                                                               tempf:=chr(ch); 
                                                               temp:=temp+tempf; 
                                                              application.ProcessMessages; 
                                                            end; 
                                                        vflag:=postdata(vurl,vfilename,temp,'0'); 
                                                        end 
                                                      else 
                                                             begin 
                                                             j:=0; 
                                                                while not eof(f) do 
                                                                begin 
                                                                  read(f,ch); 
                                                                tempf:=chr(ch); 
                                                                temp:=temp+tempf; 
                                                                j:=j+1; 
                                                                application.ProcessMessages; 
                                                      vflag:=postdata(vurl,vfilename,temp,'-2'); 
                                                    end; 
                                                   end 
                                                   else if y<> filenum then //中间包 
                                                       begin 
                                                          for i:=1 to basenum do 
                                                            begin 
                                                               read(f,ch); 
                                                              tempf:=chr(ch); 
                                                               temp:=temp+tempf; 
                                                                application.ProcessMessages; 
                                                            end; 
                                                              vflag:=postdata(vurl,vfilename,temp,'1'); 
                                                      end 
                                                   else  //最后一个包 
                                                     begin 
                                                            j:=0; 
                                                            while not eof(f) do 
                                                           begin 
                                                             read(f,ch); 
                                                             tempf:=chr(ch); 
                                                             temp:=temp+tempf; 
                                                             j:=j+1; 
                                                              application.ProcessMessages; 
                                                         end; 
                                                       vflag:=postdata(vurl,vfilename,temp,'-1'); 
                                                     end; 
                                           end; 
                                    end; 
                                    ③另一个文件用来将小数据包按照http格式封装成二进制文件上传数据流发送到指定的接收页面(URL),数据流除必要的头信息,包含两个表单城,一个数据块,其中一个表单域用来传递文件标记,用来区分本数据包是第一个包,中间包还是最后一个包,另一个表单域传递上传文件名,其关键代码如下: 
                                       try 
                                         filedata.Seek(0,sofrombeginning); 
                                         tempstring:=''; 
                                         tempstring:=tempstring+'------------------------------7cf87224d2020a'+ 
                                             newline; 
                                         tempstring:=tempstring+'Content-Disposition: form-data;name="vflag"'+newline; 
                                         tempstring:=tempstring+''+newline; 
                                         tempstring:=tempstring+vflag+newline; 
                                         tempstring:=tempstring+''+newline; 
                                         tempstring:=tempstring+''+newline; 
                                         tempstring:=tempstring+'Content-Disposition: form-data; name="editfilename"; filename="'+infile+'"'+newline; 
                                         tempstring:=tempstring+'Content-Type: application/octet-stream'+newline; 
                                         tempstring:=tempstring+''+newline; 
                                         fillchar(temparray,sizeof(temparray),#0); 
                                         strpcopy(temparray,tempstring); 
                                         request.Write(temparray,length(tempstring)); 
                                         request.seek(0,sofromend); 
                                         request.CopyFrom(filedata,filedata.size); 
                                         tempstring:=''; 
                                         tempstring:=tempstring+''+newline; 
                                         tempstring:=tempstring+'------------------------------7cf87224d2020a--' 
                                              +newline; 
                                         fillchar(temparray,sizeof(temparray),#0); 
                                         strpcopy(temparray,tempstring); 
                                         request.write(temparray,length(tempstring)); 
                                         try 
                                           http.Post(url,request,response); 
                                           if pos('成功',response.datastring)<>0 then 
                                              flag:=1 
                                         end. 
                                    End. 
                                    ④本ActiveX控件特色:可以实时显示上传进度,并能随时中断文件的上传,上传页面画面如图所示,可不能随时中断文件上传,即应用程序能随时从循环语句中跳出,在循环语句中使用了ayydicdition Process Messages语句,该语句用来监听和处理系统消息这样就有效避免了文件上传时,不能进行系统的其它操作。 
                                    3.用VB6.0开发服务器端接收文件的Activeex dll,主要利用VB6.0强大的网页操作功能,引用库文件microsoft Active sever Page object library。其中包含有asp对象Asp library request。创建一个接收函数load,使用request对象读取上传给接收页面的二进制数据流,分离出上传标志、上传文件名以及文件内容,根据上传标志将分段传送来的文件内容拼接成一个完整的文件,保存到指定目录。 
                                    四、几点说明: 
                                        1.本程序在操作系统为Win98 Win2000的客户端机器,IIS服务器端为Win 2000的环境下调试通过; 
                                    2.将upfile.htm,upload.asp,myget.dll,upfileproj1.ocx文件放置到IIS服务之虚拟目录upfile下(缺省目录为C:"Inetpub"unnroot"upfile); 
                                    3.修改upfile.htm中codebase属性(缺省为http://11.68.17.80/upfile/upfileproj1.ocx)中的IP地址为服务器端地址; 
                                    4.修改delphi工程文件upfileprojl中的upfilelmpl1文件中的Button2 click事件中的vul:string=’http://11.68.17.80/upfile/upload.asp’一行数据,将其中的IP地址转接为服务器端地址,重新编译后将upfrleprojl.ocx放置到虚拟目录下; 
                                    5.上传文件在服务器端的默认保存目录为c:"temp; 
                                    6.须手工注册myget.dll,命令语句为regsvr32  C:"inetpub"wwwroot"upfile"myget.dll 
                                    7.览器中敲击网站地址执行,缺省地址为http://11.68.17.80/upfile/upfile.htm。  |