Asp无组件上传进度条解决方案
2023-06-13 09:13:57 时间
我还是一点一点用一个实例来说明的吧,客户端HTML如下。要浏览上传附件,我们通过<inputtype="file">元素,但是一定要注意必须设置form的enctype属性为"multipart/form-data":
<formmethod="post"action="upload.asp"enctype="multipart/form-data">
<label>
<inputtype="file"name="file1"/>
</label>
<br/>
<inputtype="text"name="filename"value="defaultfilename"/>
<br/>
<inputtype="submit"value="Submit"/>
<inputtype="reset"value="Reset"/>
</form>
在后台asp程序中,以前获取表单提交的ASCII数据,非常的容易。但是如果需要获取上传的文件,就必须使用Request对象的BinaryRead方法来读取。BinaryRead方法是对当前输入流进行指定字节数的二进制读取,有点需要注意的是,一旦使用BinaryRead方法后,再也不能使用Request.Form或Request.QueryString集合了。结合Request对象的TotalBytes属性,可以将所有表单提交的数据全部变成二进制,不过这些数据都是经过编码的。首先让我们来看看这些数据是如何编码的,有无什么规律可循,编段代码,在代码中我们将BinaryRead读取的二进制转化为文本,输出出来,在后台的upload.asp中(注意该示例不要上传大文件,否则可能会造成浏览器死掉):
<%
DimbiData,PostData
Size=Request.TotalBytes
biData=Request.BinaryRead(Size)
PostData=BinaryToString(biData,Size)
Response.Write"<pre>"&PostData&"</pre>" "使用pre,原样输出格式
"借助RecordSet将二进制流转化成文本
FunctionBinaryToString(biData,Size)
ConstadLongVarChar=201
SetRS=CreateObject("ADODB.Recordset")
RS.Fields.Append"mBinary",adLongVarChar,Size
RS.Open
RS.AddNew
RS("mBinary").AppendChunk(biData)
RS.Update
BinaryToString=RS("mBinary").Value
RS.Close
EndFunction
%>
简单起见,上传一个最简单的文本文件(G:\homepage.txt,内容为"宝玉:
-----------------------------7d429871607fe
Content-Disposition:form-data;name="file1";filename="G:\homepage.txt"
Content-Type:text/plain
宝玉:
Content-Disposition:form-data;name="filename"
defaultfilename
-----------------------------7d429871607fe--
可以看出来对于表单中的项目,是用过"-----------------------------7d429871607fe"这样的边界来分隔成一块一块的,每一块的开始都有一些描述信息,例如:Content-Disposition:form-data;name="filename",在描述信息中,通过name="filename"可以知道表单项的name。如果有filename="G:\homepage.txt"这样的内容,说明是一个上传的文件,如果是一个上传的文件,那么枋鲂畔⒒岫嘁恍?ontent-Type:text/plain来描述文件的Content-Type。描述信息和主体信息之间是通过换行来分隔的。
嗯,基本上清晰了,根据这个规律我们就知道该怎么来分离数据,再对分离的数据进行处理了,不过差点忽略一个问题,就是边界值(上例中的"-----------------------------7d429871607fe")是怎么知道的?每次上传这个边界值是不一样的,还好还好asp中可以通过Request.ServerVariables("HTTP_CONTENT_TYPE")来获之,例如上例中HTTP_CONTENT_TYPE内容为:"multipart/form-data;boundary=---------------------------7d429871607fe",有了这个,我们不仅可以判断客户端的form中有无使用enctype="multipart/form-data"(如果没有使用,那么下面就没必要执行啦),还可以获取边界值boundary=---------------------------7d429871607fe。(注意:这里获取的边界值比上面的边界值开头要少"--",最好补充上。)
至于如何分析数据的过程我就不多赘述了,无非就是借助InStr,Mid等这样的函数来分离出来我们想要的数据。
二、分块上传,记录进度
要实时反映进度条,实质就是要实时知道当前服务器获取了多少数据?再回想一下我们实现上传的过程,我们是通过Request.BinaryRead(Request.TotalBytes)来实现的,在Request的过程中我们无法得知当前服务器获取了多少数据。所以只能通过变通的方法了,如果我们可以将获取的数据分成一块一块的,然后根据已经上传的块数我们就可以算出来当前上传了多大了!也就是说,如果我1K为1块,那么上传1MB的输入流就分成1024块来获取,例如我当前已经获取了100块,那么就表明当前上传了100K。当我提出分块的时候很多人觉得不可思议,因为他们都忽略BinaryRead方法不仅是可以读取指定大小,而且可以连续读取的。
写个例子来验证一下分块读取的完整性,在刚才的例子基础上(注意该示例不要上传大文件,否则可能会造成浏览器死掉):
<%
DimbiData,PostData,TotalBytes,ChunkBytes
ChunkBytes=1*1024 "分块大小为1K
TotalBytes=Request.TotalBytes "总大小
PostData="" "转化为文本类型后的数据
ReadedBytes=0 "初始化为0
"分块读取
DoWhileReadedBytes<TotalBytes
biData=Request.BinaryRead(ChunkBytes) "当前块
PostData=PostData&BinaryToString(biData,ChunkBytes)"将当前块转化为文本并拼接
ReadedBytes=ReadedBytes+ChunkBytes"记录已读大小
IfReadedBytes>TotalBytesThenReadedBytes=TotalBytes
Loop
Response.Write"<pre>"&PostData&"</pre>" "使用pre,原样输出格式
"将二进制流转化成文本
FunctionBinaryToString(biData,Size)
ConstadLongVarChar=201
SetRS=CreateObject("ADODB.Recordset")
RS.Fields.Append"mBinary",adLongVarChar,Size
RS.Open
RS.AddNew
RS("mBinary").AppendChunk(biData)
RS.Update
BinaryToString=RS("mBinary").Value
RS.Close
EndFunction
%>
试验一下上传刚才的文本文件,输出结果证明这样分块读取的内容是完整的,并且在While循环中,我们可以在每次循环时将当前状态记录到Application中,然后我们就可以通过访问该Application动态获取上传进度条。
另:上例中是通过字符串拼接的,如果是要拼接二进制数据,可以通过ADODB.Stream对象的Write方法,示例代码如下:
SetbSourceData=createobject("ADODB.Stream")
bSourceData.Open
bSourceData.Type=1"Binary
DoWhileReadedBytes<TotalBytes
biData=Request.BinaryRead(ChunkBytes)
bSourceData.WritebiData"直接使用write方法将当前文件流写入bSourceData中
ReadedBytes=ReadedBytes+ChunkBytes
IfReadedBytes>TotalBytesThenReadedBytes=TotalBytes
Application("ReadedBytes")=ReadedBytes
Loop
三、保存上传的文件
通过Request.BinaryRead获取提交数据,分离出上传文件后,根据数据类型的不同,保存方式也不同:
对于二进制数据,可以直接通过ADODB.Stream对象的SaveToFile方法,将二进制流保存成为文件。
对于文本数据,可以通过TextStream对象的Write方法,将文本数据保存到文件中。
对于文本数据和二进制数据,是可以方便的相互转换的,对于上传小文件来说,两者基本上没什么差别。但是两种方式保存时还是有一些差别的,对于ADODB.Stream对象,必须将所有数据全部装载完才可以保存成文件,所以使用这种方式如果上传大文件将很占用内存,而对于TextStream对象,可以在文件创建好后,一次Write一部分,分多次Write,这样的好处是不会占用服务器内存空间,结合上面分析的分块获取数据原理,我们可以每获取一块上传数据就将之Write到文件中。我曾做过试验,同样本机上传一个200多MB的文件,使用第一种方式内存一直在涨,到最后直接提示计算机虚拟内存不足,最可恨是即使进度条表示文件已经上传完,但是最终文件还是没有保存上。而使用后一种方法,上传过程中内存基本上无什么变化。
相关文章
- ASP如何连接MySQL数据库(asp怎么连接mysql)
- ASP操作Oracle数据库(asp链接oracle)
- asp.net的web服务MSSQL检测ASP.NET的Web服务——利用它构建更棒的站点(mssql检测基于)
- 数据交互实现ASP页面与MySQL数据交互最佳方法(asp页面与mysql)
- ASP连接MySQL失败排查与解决方案(asp连接mysql失败)
- ASP技术可以驱动MySQL吗(asp能连接mysql吗)
- ASP操作MySQL数据库实现简单便捷功能(asp用mysql数据库)
- MySQL重新梳理ASP源码转换指南(asp源码转mysql)
- ASP技术点缀MySQL之美展示精彩绚丽(asp展示mysql)
- ASP与MySQL的联合开发实现轻松跨平台互联网应用(asp和mysql)
- ASP把信息写入MySQL库的方法(asp写信息到mysql)
- ASP与DW结合MySQL实现强大网站开发(asp dw mysql)
- 使用ASP连接Oracle报错解决方案(asp连oracle报错)
- ASP操作Oracle 轻松实现查询驱动结果(asp查询oracle)
- 在ASP处理程序时显示进度
- asp.net上传大文件解决方案
- asp下用datediff实现计算两个时间差的函数
- 通过客户端验证上传图片文件大小的ASP源码
- asp.netslickupload使用方法(文件上传)
- asp.net上传图片并同时生成缩略图的代码
- asp.netUpdatePanel实现无刷新上传图片
- asp.net上传图片保存到数据库的代码
- asp.net中Request.QueryString与Request.Param的区别分析
- ASP改良版MD5、SHA256多重加密类(二次及多次)
- ASP.NET对HTML页面元素进行权限控制(二)
- 使用ASP.NET.4.5.1+MVC5.0搭建一个包含Ninject框架项目