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

一、无组件上传的原理
我还是一点一点用一个实例来说明的吧,客户端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"这样的内容,说明是一个上传的文件,如果是一个上传的文件,那么枋鲂畔⒒岫嘁恍蠧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方法不仅是可以读取指定大小,而且可以连续读取的。

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

<%
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的文件,使用第一种方式内存一直在涨,到最后直接提示计算机虚拟内存不足,最可恨是即使进度条表示文件已经上传完,但是最终文件还是没有保存上。而使用后一种方法,上传过程中内存基本上无什么变化。

(0)

相关推荐

  • 在无组件的情况下,如何上传图片?

    <html> <head> <title>星河影动</title> </head> <body> <tr> <td height="69"><p align="center">撼雪喷云之无组件上传图片</font></td> </tr> <tr> <td height="9"> &

  • 无组件生成缩略图

    网上有不少生成缩略图的ASP组件.若你的虚拟空间不支持注册新组件,可能会感觉自己的网站失色不少.心晴不才,结合网上资源写了个无组件生成缩略图程序,仅供参考. 还是先看看基础部分吧.首先,我们知道在页面中显示图片是如下代码: <img src="pic.gif" border="0" width="300" height="260"> src是图片路径,border控制图片边缘宽度,width是图片的长度,heigh

  • 无组件上传图片之文件采用方案

    首先,图片在页面中能查找选择.设计表单页面index.asp和上传选择页upload.asp,upload.asp在index.asp中以iframe包含. 其次,所选图片应能上传到某文件夹.建立一文件夹uploadimg 最后,传上去的图片应如何引用?很显然,采用UBB立即显示.upload.asp的指向对象upfile.asp具有写入UBB标签的功能. 无组件上传调试文件夹    -- index.asp    -- upload.asp    -- upfile.asp    -- upl

  • Asp无组件生成缩略图的代码

    还是先看看基础部分吧.首先,我们知道在页面中显示图片是如下代码: <img src="pic.gif" border="0" width="300" height="260"> src是图片路径,border控制图片边缘宽度,width是图片的长度,height是图片的高度.缩略图的生成其实就是在原始尺寸上缩放.但一般为了尽量少失真,我们都会按比例缩放.于是,获取图片的长宽尺寸也就成了生成缩略图的重点. 下面便是编

  • 无组件实现文件上传/下载

    ' 用ASP实现无组件上传/下载文件  '  ' 功能简介   ' 将上传的文件数据保存到数据库中,可以处理表单中的多个上传文件的情况  ' 适用于各种数据库,使用ADO的方法连接数据库  ' 本示例中使用的是ACCESS数据库:zj.mdb  ' 表:tb_img(id int(自增列),path text(255) 保存上传文件的目录  ' ,fname text(250) 保存上传的文件名,type test(250) 保存上传文件的类型  ' ,img ole对象 保存上传的文件内容 

  • ASP无组件分页实现思路及代码

    MVC下: 后台代码: 复制代码 代码如下: public ActionResult sys(string page) { if (page == null) { string sql = "select top 15 * from dingdinfo ORDER BY dingdh desc"; ViewData["ds"] = dr.resultSet(sql, "dingdinfo"); } if (page != null) { int

  • asp无组件生成验证码 GIF图片格式

    复制代码 代码如下: <% Option Explicit ' 显示声明 Class Com_GifCode_Class ''''''''''''''''''''''''''''''''''''''''''''' ' Author: Layen support@ssaw.net 84815733(QQ) ' Thanks: Laomi, Laomiao, NetRube ' 2006-01-02 ''''''''''''''''''''''''''''''''''''''''''''' Publ

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

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

  • windows2008+iis7无组件上传写入文件失败ADODB.Stream 错误 800a0bbc问题

    现象:写入文件失败,ADODB.Stream 错误 800a0bbc 条件:在已排除一般的解决方法文件夹权限后,并且服务器为windows2008 希望写这文章可以让大家避免浪费太多时间,最快地解决问题. 一个ASP程序用到无组件上传,在本地XP SP3 IIS5.1及在Windows Server 2003 + IIS6.0上测试均为可以正常上传.到把程序放了windows2008+IIS7.0上发现内部服务器错误500,最后我把其调为可显示详细错误信息,显示为: 写入文件失败,ADODB.S

  • PHP中使用Session配合Javascript实现文件上传进度条功能

    Web应用中常需要提供文件上传的功能.典型的场景包括用户头像上传.相册图片上传等.当需要上传的文件比较大的时候,提供一个显示上传进度的进度条就很有必要了. 在PHP 5.4以前,实现这样的进度条并不容易,主要有三种方法: 1.使用Flash, Java, ActiveX 2.使用PHP的APC扩展 3.使用HTML5的File API 第一种方法依赖第三方的浏览器插件,通用性不足,且易带来安全隐患.不过由于Flash的使用比较广泛,因此还是有很多网站使用Flash作为解决方案. 第二种方法的不足

  • 关于用ADO STREAM做的无组件上传程序简单介绍

    前面有人贴了用ADO STREAM做的无组件上传程序,今天我做一下关于它的简单介绍 以前,如果要用ASP操作文件,比如移动.复制.删除或者创建一个记事本文件,基本上都是通过FILESYSTEMOBJECT对象做的,当然,这个东西很专业,也没说什么不好,它可以提供完善的文件信息,比如建立时间,大小,上次修改时间等等,但是如果你不做痛苦的高代价的字符格式转换的话,利用它你无法直接操作二进制文件. 但是,现在我们介绍的stream物件可以同时操作文本对象和二进制对象,要求是您的机器上要安装有ADO2.

  • 使用php+apc实现上传进度条且在IE7下不显示的问题解决方法

    今天整理以前写过的关于上传文件,并显示进度条的程序代码,对该代码进行优化整理.解决了一直困扰的问题:有时进度条没有达到100%,浏览器出现假死现象.在IE8.chrome测试非常完美. 项目需求: 上传APK,显示上传进度条,上传完成开始分析APK,并显示:正在分析apk数据,请稍后... ,分析完成后,显示:上传成功,重新上传 由于我电脑装的是winxp英文版,IE默认的是IE7,在测试的时候发现进度条不显示.百分比也不显示. 排除问题: 1.将DOM改成jquery方式,不显示 2.给递归调

  • HTML5 Ajax文件上传进度条如何显示

    原本打算使用jquery插件进行异步文件上传,比如uploadfy但是需要额外的支持,也有人用iframe模仿异步上传机制,感觉都比较别扭.因为项目不考虑低版本浏览器,所以决定用html5实现.下面只是一个简单的demo,具体样式需要自己去做. 后台基于strut2进行文件处理,具体因项目而定.只是要注意设置文件大小的限制.  <constant name="struts.multipart.maxSize" value="52428800"/>这个配置

  • js HTML5 Ajax实现文件上传进度条功能

    本文实例介绍了js结合HTML5 Ajax实现文件上传进度条功能,分享给大家供大家参考,具体内容如下 1.  lib.js var Host = window.location.host; //--Cookie function setCookie(name,value) { var Days = 30; var exp = new Date(); exp.setTime(exp.getTime() + Days*24*60*60*1000); document.cookie = name +

  • PHP利用APC模块实现文件上传进度条的方法

    本文实例讲述了PHP利用APC模块实现文件上传进度条的方法.分享给大家供大家参考.具体分析如下: 以前的php5.2之前的版本是不能可使用APC模块的,因为之前的压根就没有这个APC模块,如果想使用APC模块实现上传进度条我们必须是php5.2或更高版本. 从5.2开始APC加入了一个叫APC_UPLOAD_PROGRESS的东东,解决了困扰大家已久的进度条问题.并且它把原来的上传时把临时文件全部缓存到内存改成了当临时文件达到设定值时就自动保存到硬盘,有效地改善了内存利用状况. 它的作用原理是在

  • PHP+apc+ajax实现的ajax_upload上传进度条代码

    本文实例讲述了PHP+apc+ajax实现的ajax_upload上传进度条代码.分享给大家供大家参考,具体如下: 上传进度条是怎么实现的呢?原理是怎么样的呢?当我们浏览,选择上传后,会产生一个临时文件,上传的时把这个临时文件,上传到服务器,上传完成后,这个临时文件会被删除掉.如果我们能读取这个临时文件的大小,就知道上传进度是多少了,php apc模块可以实现这个功能. 一.安装apc模块 下载地址:http://pecl.php.net/package/apc tar zxvf APC-3.1

  • PHP 文件上传进度条的两种实现方法的代码

    目前我知道的方法有两种,一种是使用PHP的创始人 Rasmus Lerdorf 写的APC扩展模块来实现(http://pecl.php.net/package/apc),另外一种方法是使用PECL扩展模块 uploadprogress实现(http://pecl.php.net/package/uploadprogress)我这里举两个分别实现的例子供参考,更灵活的应用根据自己需要来修改. APC实现方法: 安装APC,参照官方文档安装,可以使用PECL模块安装方法快速简捷,这里不说明 配置p

随机推荐