一、无组件上传的原理
我还是一点一点用一个实例来说明的吧,客户端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,内容为"宝玉:http://www.webuc.net")来试验一下,文本框filename中保留默认值"defaultfilename",提交看看输出结果:
-----------------------------7d429871607fe
Content-Disposition:form-data;name="file1";filename="G:\homepage.txt"
Content-Type:text/plain
宝玉:http://www.webuc.net
-----------------------------7d429871607fe
Content-Disposition:form-data;name="filename"
defaultfilename
-----------------------------7d429871607fe--
可以看出来对于表单中的项目,是用过"-----------------------------7d429871607fe"这样的边界来分隔成一块一块的,每一块的开始都有一些描述信息,例如:Content-Disposition:form-data;name="filename",在描述信息中,通过name="filename"可以知道表单项的name。如果有filename="G:\homepage.txt"这样的内容,说明是一个上传的文件,如果是一个上传的文件,那么描述信息会多一行Content-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的文件,使用第一种方式内存一直在涨,到最后直接提示计算机虚拟内存不足,最可恨是即使进度条表示文件已经上传完,但是最终文件还是没有保存上。而使用后一种方法,上传过程中内存基本上无什么变化。
Q:进度信息如何访问?
A:进度信息保存在Application中,每次上传时生成一个进度ID,根据这个进度ID可以检索Application中的当前上传进度信息。
Q:进度信息以什么形式保存在Application中?
A:Asp太弱了,我分别试过Scripting.Dictionary和XMLDom,但是Asp中Application不能保存这种对象,要是asp.net就直接可以用Hashtable了。最后是在Application中用一个ADODB.Recordset对象来保存进度相关信息。
Q:怎么保证的页面能即时反应显示进度条信息?
A:
文件开头加上声明来关闭会话状态
要保证禁用缓存:
Response.CacheControl="no-cache"
Response.Expires=-1
Q:可以上传多大文件?
A:这个和网速,服务器内存等多方面因素有关,将Server.ScriptTimeout设置足够长,那么理论上可以和服务器保持连接很长时间。因为在asp中,不能实现对文件的“追加”写入,必须将所有待写入文件的数据都先保存在内存,这样如果上传大文件,那么将很占用服务器内存(文本文件可以使用TextStream.Write追加写入)。在asp.net下就比较爽了,分块读取的时候,每读一块分析一块,然后将上传文件的数据内容“追加”写入硬盘文件中,对内存占用很小很小。一般几十MB的文件还是没问题,太大的上传其实对于web下也不是很有意义。
让asp.net默认的上传组件支持进度条反映
对于web下的上传,实际上更多的时候不用上传太大东西,asp.net默认的上传组件足够用了,美中不足就是没有上传进度反映,所以现在要做的就是在asp.net默认的上传基础上加上进度反映。
关于web上传的原理,曾在以前有深入分析过《asp无组件上传进度条解决方案》《Asp无组件上传带进度条(续)》,并有写过asp版的无组件上传进度条,在这里就不多赘述。相信很多人都看过思归发的《用ASP.NET上传大文件》,解决的方法是利用隐含的HttpWorkerRequest,用它的GetPreloadedEntityBody和ReadEntityBody方法从IIS为ASP.NET建立的pipe里分块读取数据,对于每块分块进行分析并存储为临时文件,相对比较复杂。
要实现进度条的实时反映,核心的技术就是对上传的数据进行“分块”读取,在读取每块数据时记录当前已上传的块数,根据分块的大小,即可知道已上传的大小,根据总大小,即可知道当前上传的进度。具体的技术还是利用隐含的HttpWorkerRequest,用它的GetPreloadedEntityBody和ReadEntityBody方法从IIS为ASP.NET建立的pipe里分块读取数据,只不过仅仅是分块和记录已上传块数而已,用不着对已上传的数据进行分析和处理,因为这部分复杂的工作已经由asp.net的上传组件给我们做了。
根据上面所述的原理,具体代码相对很简单,我写了一个例子,用一个专门的进度显示页面(Progress.aspx),通过定时刷新(XmlHttp,FF支持)来获取当前上传的进度信息,并实时反映到上传页面上。
代码下载(解压后给web目录设置虚拟目录为“Upload”即可),其中进度条我是用脚本来实现的,单独的进度条脚本代码:
http://www.webuc.net/myproject/progressbar/progressinfo.htm
http://www.webuc.net/myproject/progressbar/progressbar.rar
分享到:
相关推荐
ASP无组件上传带进度条是一种在ASP(Active Server Pages)环境下实现文件上传并显示上传进度的技术,无需额外的服务器组件。这种技术对于提高用户体验尤其重要,因为它允许用户在上传大文件时了解进度,减少了用户...
在传统的ASP中,文件上传通常需要借助第三方组件如ASPUpload或FreeASPUpload等,但"无组件"意味着我们将探讨一种不依赖额外组件的解决方案。 【描述】"无组件上传带进度条"表明我们要实现的是一个基于ASP的文件上传...
为了解决这一问题,ASP(Active Server Pages)结合AJAX(Asynchronous JavaScript and XML)技术,实现了无刷新文件上传,同时还提供了进度条显示,提高了交互性。本文将深入探讨这种技术的实现原理及步骤。 一、...
这个"ASP无组件上传带进度条"的源码和实例,很可能包含了一套这样的解决方案。 在前端,可能使用了HTML5的File API来获取选中的文件信息,并通过AJAX异步上传文件,同时利用JavaScript或者jQuery等库来创建和更新...
【Asp无组件上传带进度条】是一种在ASP(Active Server Pages)环境下实现文件上传并显示上传进度的技术,它不需要额外的服务器控件或者组件。这种方法的关键在于通过分块读取上传文件并实时更新进度信息,以实现...
ASP无组件上传带真实进度条_upload是一个针对ASP(Active Server Pages)开发的文件上传解决方案,它无需额外的组件或插件即可实现文件上传,并且具备显示真实上传进度条的功能。在传统的ASP应用中,文件上传通常...
"风声无组件上传 ASP" 是一个解决方案,它允许开发者在不依赖额外组件的情况下实现文件上传功能。在传统的 ASP 文件上传中,通常会使用第三方组件如Upload或CFUpload,但这些组件可能需要额外的购买和安装步骤。风声...
1. **选择合适的控件**:在Asp.net中,我们可以使用第三方控件如Telerik、DevExpress等提供的进度条组件,或者使用HTML5的Progress元素结合Ajax技术来创建自定义的上传进度条。本例中提到的"ProgressBar.dll"可能是...
"asp带进度条的上传无组件类"是一个解决方案,它允许在ASP环境中实现文件上传并显示上传进度,而无需额外安装服务器组件。这种技术的核心在于通过JavaScript或AJAX来实现前端的进度条展示,并通过服务器端的脚本处理...
"艾恩Ajax无刷新文件上传(带进度条,无组件)"就是这样一个解决方案,它不仅实现了无刷新的上传,还提供了文件上传进度条,让用户在等待文件上传过程中能够实时了解进度。 ### 1. Ajax基础 Ajax的核心是通过...
在ASP中实现文件上传功能,通常需要借助组件,如Upload、CFtp等,但这里提到的是“一个成功的asp无组件上传代码”,意味着它提供了一种无需额外组件的文件上传解决方案。这种技术对于那些不希望或不能安装服务器组件...
【Flash分类列表带进度条无组件批量上传】是一种在网页上实现大文件或者多文件高效上传的技术方案,尤其适用于ASP、PHP、JSP和ASP.NET等服务器端编程语言的环境。这种技术允许用户一次性选择多个文件,并在上传过程...
总结,Flash多文件上传组件结合进度条功能,是早期Web开发中解决文件上传问题的有效方案。虽然随着HTML5技术的发展,Flash逐渐被淘汰,但它的设计理念和实现方式仍对现代Web开发有借鉴意义。对于还在使用Flash的项目...
标题"fileup.rar_ASP 上传文件_asp 上传_上传 asp_上传 进度条_文件上传"暗示了这是一个关于ASP文件上传的解决方案,而且还特别提到了“带有进度条”,这意味着该示例可能包含了在上传过程中展示进度反馈的功能,以...
【描述】"带进度条的ASP.NET上传"指的是在ASP.NET环境中开发的一种文件上传解决方案,它通过在上传过程中展示进度条来增强用户体验。通常,传统的文件上传操作会隐藏实际的进度,让用户感觉等待时间较长。而此解决...
在本项目中,"asp.net带进度条上传组件"是一个针对批量图片上传的解决方案,它包含了一个关键特性:实时显示上传进度。这为用户提供了一种交互式的体验,使他们能够跟踪文件上传的状态,从而提升用户体验。 在ASP...
**Ajax无刷新文件上传技术详解** ...总的来说,Ajax无刷新文件上传结合HTML5的File API和XMLHttpRequest2,为Web应用提供了一种高效、便捷的文件上传解决方案,尤其适用于需要实时反馈和良好用户体验的应用场景。
ASP带进度条上传文件系统是一种基于Active Server Pages (ASP)技术的文件上传解决方案,它为用户提供了一种直观的上传进度指示,增强了用户体验。在传统的文件上传过程中,用户往往无法得知文件上传的具体进度,而带...