`
lzrzhao
  • 浏览: 69027 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

无组件上传进度条解决方案

 
阅读更多
无组件上传进度条解决方案

一、无组件上传的原理

我还是一点一点用一个实例来说明的吧,客户端HTML如下。要浏览上传附件,我们通过<input type="file">元素,但是一定要注意必须设置form的enctype属性为"multipart/form-data":


<form method="post" action="upload.asp" enctype="multipart/form-data">
 <label>
  <input type="file" name="file1" />
 </label>
 <br />
 <input type="text" name="filename" value="default filename"/>
 <br />
 <input type="submit" value="Submit"/>
 <input type="reset" value="Reset"/>
</form>

在后台asp程序中,以前获取表单提交的ASCII 数据,非常的容易。但是如果需要获取上传的文件,就必须使用Request对象的BinaryRead方法来读取。BinaryRead方法是对当前输入流进行指定字节数的二进制读取,有点需要注意的是,一旦使用BinaryRead 方法后,再也不能使用Request.Form 或 Request.QueryString 集合了。结合Request对象的TotalBytes属性,可以将所有表单提交的数据全部变成二进制,不过这些数据都是经过编码的。首先让我们来看看这些数据是如何编码的,有无什么规律可循,编段代码,在代码中我们将BinaryRead读取的二进制转化为文本,输出出来,在后台的upload.asp中(注意该示例不要上传大文件,否则可能会造成浏览器死掉):
<%
Dim biData, PostData
Size = Request.TotalBytes
biData = Request.BinaryRead(Size)
PostData = BinaryToString(biData,Size)
Response.Write "<pre>" & PostData & "</pre>"  '使用pre,原样输出格式
' 借助RecordSet将二进制流转化成文本
Function BinaryToString(biData,Size) 
 Const adLongVarChar = 201
 Set RS = 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
End Function 
%>

简单起见,上传一个最简单的文本文件(G:/homepage.txt,内容为"宝玉:http://www.webuc.net")来试验一下,文本框filename中保留默认值"default filename",提交看看输出结果:

-----------------------------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"
default filename
-----------------------------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方法不仅是可以读取指定大小,而且可以连续读取的。

写个例子来验证一下分块读取的完整性,在刚才的例子基础上(注意该示例不要上传大文件,否则可能会造成浏览器死掉):

<%
Dim biData, PostData, TotalBytes, ChunkBytes
ChunkBytes = 1 * 1024     ' 分块大小为1K
TotalBytes = Request.TotalBytes  ' 总大小
PostData = ""         ' 转化为文本类型后的数据
ReadedBytes = 0        ' 初始化为0
' 分块读取
Do While ReadedBytes < TotalBytes
 biData = Request.BinaryRead(ChunkBytes)  ' 当前块
 PostData = PostData & BinaryToString(biData,ChunkBytes) ' 将当前块转化为文本并拼接
 ReadedBytes = ReadedBytes + ChunkBytes ' 记录已读大小
 If ReadedBytes > TotalBytes Then ReadedBytes = TotalBytes
Loop
Response.Write "<pre>" & PostData & "</pre>"  ' 使用pre,原样输出格式
' 将二进制流转化成文本
Function BinaryToString(biData,Size) 
 Const adLongVarChar = 201
 Set RS = 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
End Function 
%>
试验一下上传刚才的文本文件,输出结果证明这样分块读取的内容是完整的,并且在While循环中,我们可以在每次循环时将当前状态记录到Application中,然后我们就可以通过访问该Application动态获取上传进度条。

另:上例中是通过字符串拼接的,如果是要拼接二进制数据,可以通过ADODB.Stream对象的Write方法,示例代码如下:

Set bSourceData = createobject("ADODB.Stream")
bSourceData.Open
bSourceData.Type = 1 'Binary
Do While ReadedBytes < TotalBytes
 biData = Request.BinaryRead(ChunkBytes)
 bSourceData.Write biData ' 直接使用write方法将当前文件流写入bSourceData中
 ReadedBytes = ReadedBytes + ChunkBytes
 If ReadedBytes > TotalBytes Then ReadedBytes = TotalBytes
 Application("ReadedBytes") = ReadedBytes
Loop

三、保存上传的文件

通过Request.BinaryRead获取提交数据,分离出上传文件后,根据数据类型的不同,保存方式也不同:
  • 对于二进制数据,可以直接通过ADODB.Stream对象的SaveToFile方法,将二进制流保存成为文件。
  • 对于文本数据,可以通过TextStream对象的Write方法,将文本数据保存到文件中。

对于文本数据和二进制数据,是可以方便的相互转换的,对于上传小文件来说,两者基本上没什么差别。但是两种方式保存时还是有一些差别的,对于ADODB.Stream对象,必须将所有数据全部装载完才可以保存成文件,所以使用这种方式如果上传大文件将很占用内存,而对于TextStream对象,可以在文件创建好后,一次Write一部分,分多次Write,这样的好处是不会占用服务器内存空间,结合上面分析的分块获取数据原理,我们可以每获取一块上传数据就将之Write到文件中。我曾做过试验,同样本机上传一个200多MB的文件,使用第一种方式内存一直在涨,到最后直接提示计算机虚拟内存不足,最可恨是即使进度条表示文件已经上传完,但是最终文件还是没有保存上。而使用后一种方法,上传过程中内存基本上无什么变化。

四、未解决的难题

我在博客园上看到Bestcomy描述他的Asp.Net上传组件是可以和Sever.SetTimeOut无关的,而在Asp中我是没能做到,对于上传大文件,就只有将Server.SetTimeOut设置为一个很大的值才可以。不知道有没有比较好的解决方法。

如果我们在保存文件时,使用TextStream对象的Write方法,那么如果用户上传时中断了文件传输,已经上传的那部分文件还是在的,如果可以断点续传就好了。关键问题是Request.BinaryRead方法虽然可以分块读取,但是却不能跳过某一段读取!

五、结束语

原理基本上是说清楚了,但是实际代码要比这复杂的多,要考虑很多问题,最麻烦在分析数据那部分,对于每一块获取的数据,要分析是不是属于描述信息,是表单项目还是上传的文件,文件是否已经上传结束……

相信根据上面的描述,您也可以开发出您自己功能强大的无组件上传组件。我想更多的人关心的只是代码,而不会自己动手去写的,也许没有时间,也许水平还不够,更多的只是已经成为了一种习惯……我在CSDN上见过太多技术八股文——一段说明,然后全是代码。授人以鱼不若授人以渔,给你一个代码,也许你并不会去思考为什么,直接拿去用,当下次碰到类似的问题的时候,还是不知道为什么,希望此文能让更多人学到点什么,最重要是“悟”到点什么!

完整代码整理完善中……

分享到:
评论

相关推荐

    Asp无组件上传进度条解决方案

    ### ASP无组件上传进度条解决方案详解 #### 一、引言 在早期的Web开发中,ASP(Active Server Pages)是一种广泛使用的服务器端脚本环境,用于创建动态网页。随着互联网技术的发展,用户对交互性及用户体验的要求...

    新 ASP无组件上传带进度条 (源码 + 实例)

    ASP无组件上传带进度条是一种在ASP(Active Server Pages)环境下实现文件上传并显示上传进度的技术,无需额外的服务器组件。这种技术对于提高用户体验尤其重要,因为它允许用户在上传大文件时了解进度,减少了用户...

    无组件上传带进度条asp版

    【标题】"无组件上传带进度条asp版"所涉及的知识点主要集中在ASP(Active Server Pages)编程语言中实现文件上传的功能,同时结合了进度条显示以提供用户友好的交互体验。在传统的ASP中,文件上传通常需要借助第三方...

    ASP无组件上传带进度条(源码+实例)

    这个"ASP无组件上传带进度条"的源码和实例,很可能包含了一套这样的解决方案。 在前端,可能使用了HTML5的File API来获取选中的文件信息,并通过AJAX异步上传文件,同时利用JavaScript或者jQuery等库来创建和更新...

    asp Ajax无刷新文件上传(带进度条,无组件)

    为了解决这一问题,ASP(Active Server Pages)结合AJAX(Asynchronous JavaScript and XML)技术,实现了无刷新文件上传,同时还提供了进度条显示,提高了交互性。本文将深入探讨这种技术的实现原理及步骤。 一、...

    Asp无组件上传带进度条

    【Asp无组件上传带进度条】是一种在ASP(Active Server Pages)环境下实现文件上传并显示上传进度的技术,它不需要额外的服务器控件或者组件。这种方法的关键在于通过分块读取上传文件并实时更新进度信息,以实现...

    完美解决上传进度条和upload控件不能修改样式的问题

    传统的HTML `&lt;input type="file"&gt;` 标签往往样式单一,难以满足设计需求,而题目中提到的解决方案则解决了这一问题,允许开发者对上传控件的样式进行自定义,以匹配网站的整体设计风格,提升视觉效果。 其中,"带...

    ASP无组件上传带真实进度条_upload

    ASP无组件上传带真实进度条_upload是一个针对ASP(Active Server Pages)开发的文件上传解决方案,它无需额外的组件或插件即可实现文件上传,并且具备显示真实上传进度条的功能。在传统的ASP应用中,文件上传通常...

    风声无组件上传 asp

    "风声无组件上传 ASP" 是一个解决方案,它允许开发者在不依赖额外组件的情况下实现文件上传功能。在传统的 ASP 文件上传中,通常会使用第三方组件如Upload或CFUpload,但这些组件可能需要额外的购买和安装步骤。风声...

    艾恩Ajax无刷新文件上传(带进度条,无组件)

    "艾恩Ajax无刷新文件上传(带进度条,无组件)"就是这样一个解决方案,它不仅实现了无刷新的上传,还提供了文件上传进度条,让用户在等待文件上传过程中能够实时了解进度。 ### 1. Ajax基础 Ajax的核心是通过...

    FLASH多文件上传组件,带进度条

    总结,Flash多文件上传组件结合进度条功能,是早期Web开发中解决文件上传问题的有效方案。虽然随着HTML5技术的发展,Flash逐渐被淘汰,但它的设计理念和实现方式仍对现代Web开发有借鉴意义。对于还在使用Flash的项目...

    Flash 分类列表带进度条无组件批量上传

    总的来说,"Flash分类列表带进度条无组件批量上传"是一种增强网页上传功能的技术,通过Flash提供用户友好的界面和上传进度反馈,结合服务器端的处理代码,实现高效、安全的文件批量上传。开发者可以根据不同的服务器...

    C#批量上传 进度条(包括各种上传例子)

    在本压缩包中,可能包含了Flash技术的SWFUpload组件,这是一个早期的文件上传解决方案,它可以提供进度条反馈,但需要注意的是,Flash已逐渐被淘汰,现代浏览器可能不再支持。 5. **AS+Flash**:ActionScript(AS)...

    带进度条的上传组件

    - **FlashUp**:这个名字可能是上传组件的一个特定实现,可能是一个基于Adobe Flash的解决方案。在早期的Web开发中,Flash经常被用来实现大文件上传,因为它可以处理更大的文件大小限制和更复杂的文件类型。但是,...

    Ajax无刷新文件上传(带进度条,无组件)

    **Ajax无刷新文件上传技术详解** ...总的来说,Ajax无刷新文件上传结合HTML5的File API和XMLHttpRequest2,为Web应用提供了一种高效、便捷的文件上传解决方案,尤其适用于需要实时反馈和良好用户体验的应用场景。

    Asp.net 上传进度条

    在Asp.net开发中,有时候我们需要提供用户友好的交互体验,比如在文件上传过程中显示一个进度条,让用户知道...在实际开发中,根据具体需求和环境,可以选择适合的解决方案,如使用开源库、自定义控件或HTML5原生特性。

    无组件上传!!无组件上传!!

    综上所述,无组件上传是现代Web应用中常见的一种文件上传解决方案,它利用HTML5的新特性,提供了更安全、灵活且用户体验良好的文件上传体验。开发者在实现这一功能时,需关注安全性、用户体验以及兼容性等多个方面。

    asp带进度条的上传无组件类

    "asp带进度条的上传无组件类"是一个解决方案,它允许在ASP环境中实现文件上传并显示上传进度,而无需额外安装服务器组件。这种技术的核心在于通过JavaScript或AJAX来实现前端的进度条展示,并通过服务器端的脚本处理...

    RanUpLoad大文件上传组件(带进度条)

    特别是对于处理大文件的场景,用户往往需要一个稳定且具有用户体验友好的上传解决方案。"RanUpLoad大文件上传组件(带进度条)"正是针对这样的需求而设计的。这款组件允许用户在上传大文件时实时监控进度,提供更...

Global site tag (gtag.js) - Google Analytics