◆ [2017-12-17 星期日 2:9] ◆ 您来自:54.226.172.30,欢迎您访问風雲工作室。 收藏本站 ◆ | ◆ 设为首页
联系站长(腾讯QQ)
5029111 [風雲]
站长当前离线
首  页 论坛交流 游戏频道 无忧脚本 网络硬盘 网店精选 聊 天 室 自助链接 来访记录 访客留言 搜索提供
位置:風雲工作室 - 论坛交流 - 技术专栏 - 后台开发 - 【原创】再次用Javascript写了一个简单的asp版文字和多文件混合上传 返回
主题:【原创】再次用Javascript写了一个简单的asp版文字和多文件混合上传
Rimifon
★☆☆☆☆☆☆☆☆☆
积分:261
发帖:293
登录:2017/11/15
注册:2006/6/28
(1楼)【原创】再次用Javascript写了一个简单的asp版文字和多文件混合上传
演示地址:http://www.fengyun.org/Test/Upload.asp
仅创建了一个htmlfile的ActiveX对象,没有实现文件保存。这个代码应该比较容易看懂,其实JS做文件上传并不难。
原理是利用了recordset的appendChunk方法来连续读取上传数据,解决IIS上传默认不允许超过200kb的问题,然后使用xml分析二进制内容。
上代码吧:
<%@ language="javascript" codepage="65001" %><%
Boot();
function Boot()
{
        if(Request.QueryString("Mode").Item != "Down") return ShowForm();
        // 文件下载处理
        if(!Application("TempName")) return Response.Write("No File");
        Response.addHeader("Content-Disposition", "Attachment;filename=\"" + encodeURIComponent(Application("TempName")) + "\"");
        Response.addHeader("Content-Length", Application("TempSize"));
        Response.BinaryWrite(Application("TempFile"));
}
function ShowForm()
{ %><!doctype html><html><head>
        <meta charset="UTF-8" />
        <title>文件上传</title>
        <style type="text/css">
        body{ font: 4mm/7mm simsun }
        </style>
</head><body><%
var up = new UploadClass;
if(Request.ServerVariables("REQUEST_METHOD").Item == "POST")
{
        var str = up.ReadForm();
        if(str != "OK") Response.Write(str);
        else
        {
                var data = up.Form("test");
                if(data[0].Data) Response.Write("您提交的文本为:" + data[0] + "<br />");
                if(data[1].File)
                {
                        Response.Write("您上传的文件是:<a href=\"?Mode=Down\">" + data[1].File + "</a> (" + data[1].Size + " bytes)<br />");
                        Application("TempFile") = data[1].Data;
                        Application("TempSize") = data[1].Size;
                        Application("TempName") = data[1].File;
                }
        }
}%><form method="post" enctype="multipart/form-data">
文本:<input name="test" /><br />
文件:<input name="test" type="file" />
<input type="submit" value="上传" /><br />
当前最大允许上传 <%= up.MaxSize %> Bytes,支持的文件类型:<%= up.Filter %><%
if(Application("TempName")) Response.Write("<br />当前的临时文件为:<a href=\"?Mode=Down\">" + Application("TempName") + "</a> (" + Application("TempSize") + " Bytes)");
%>
</form></body></html><% }

/* 文件上传类,支持多文件及文字混合上传 */
function UploadClass()
{
        this.MaxSize = 512 * 1024;
        this.Filter = "jpg|png|gif|bmp|doc|docx|txt|zip|rar";
        var data = new Object;        // 存储表单对象
        this.ReadForm = function()
        {
                var nmbTotal = Request.TotalBytes;
                if(nmbTotal > this.MaxSize) return "文件大小超过限制。";
                var strRule = Request.ServerVariables("Http_Content_Type").Item || "";
                strRule = (strRule.match(/boundary=(.+)/) || [])[1];
                if(!strRule) return "非文件上传表单";
                strRule = "2d2d" + strRule.replace(/[\w\-]/g, function($1){ return $1.charCodeAt(0).toString(16); });
                var xml = new ActiveXObject("htmlfile").createElement("xml");
                var root = xml.createElement("root"); root.dataType = "bin.hex";
                var rcd = xml.recordset; rcd.fields.append("bin", 205, -1);
                rcd.open(); rcd.addNew();
                var nmbByte = 0, nmbRead = 200000;        // 缓冲区大小
                while(Response.IsClientConnected() && nmbByte < nmbTotal)
                {
                        rcd(0).appendChunk(Request.BinaryRead(nmbRead));
                        nmbByte += nmbRead;
                }
                root.nodeTypedValue = rcd(0).value; rcd.close();
                var arr = root.text.split(strRule); arr.shift(); arr.pop();
                var reg = new RegExp("\\.(?:" + this.Filter + ")$", "i");
                for(var i = 0; i < arr.length; i++)
                {
                        var nmbSplit = arr[i].indexOf("0d0a0d0a");
                        // 此处仅支持UTF-8解码,gbk请借助rcd或流对象
                        var strHead = arr[i].slice(4, nmbSplit).replace(/(\w{2})/g, "%$1");
                        strHead = decodeURIComponent(strHead);
                        var strPath = (strHead.match(/filename="(.+?)"/i) || [])[1] || "";
                        strPath = (strPath.match(/([^\\\/]+)$/) || [])[1];
                        if(strPath && !reg.test(strPath)) return "不允许的文件类型。";
                        // 查找两个空行,忽略最后一个空行
                        root.text = arr[i].slice(nmbSplit + 8, -4);
                        var field = (strHead.match(/name="(.+?)"/i) || [])[1] || "";
                        if(!data[field]) data[field] = new Array;
                        data[field].push(
                        {
                                File : strPath, Size : root.text.length / 2,
                                Data : strPath ? root.nodeTypedValue : decodeURIComponent(root.text.replace(/(\w{2})/g, "%$1")),
                                toString : function(){ return this.Data; }
                        });
                }
                return "OK";
        }
        this.Form = function(strField)
        {
                var item = data[strField] || [];
                return item.length < 2 ? item[0] : item;
        }
} %>
► 相关附件:
· Upload.rar (1.77 Kb)


时间:2013年3月21日 5:40:06 IP:已记录 引用 回复
Rimifon
★☆☆☆☆☆☆☆☆☆
积分:261
发帖:293
登录:2017/11/15
注册:2006/6/28
(2楼)
IIS默认的上传缓冲大小为200000字节,所以实际还不到200k。而下载时输出的缓冲大小为4 * 1024 * 1024字节(4M),所以如果直接Response.BinaryWrite大于4M的文件,会出现超过缓冲区大小的错误,解决的方法为:
// 保存缓存部分
Application.Lock();
var stm = Application("TempFile");
if(!stm)
{
        stm = Server.CreateObject("adodb.stream");
        stm.Type = 1; stm.Open();
        Application("TempFile") = stm;
}
stm.Position = 0; stm.SetEOS();
if(data[1].Size) stm.Write(data[1].Data);
Application("TempSize") = data[1].Size;
Application("TempName") = data[1].File;
Application.Unlock();
下载输出时,开启缓冲,并实施输送到客户端。部分代码为:
// 输出部分代码
Application.Lock();
Response.addHeader("Content-Disposition", "Attachment;filename=\"" + encodeURIComponent(Application("TempName")) + "\"");
Response.addHeader("Content-Length", Application("TempSize"));
var stm = Application("TempFile");
stm.Position = 0;
Response.Buffer = true;
while(!stm.EOS)
{
        Response.BinaryWrite(stm.Read(4 * 1024 * 1024));
        Response.Flush();
}
Application.Unlock();
如果从rs中读取二进制文件,可先用rs对象的ActualSize获取总的数据大小,然后再getChunk数据。
注意:应为文件可能较大,处理的时间会比一般情况下要长,为了防止对同一个流的操作发生冲突,建议使用Application.Lock方法。


时间:2013年3月27日 2:29:18 IP:已记录 引用 回复
Rimifon
★☆☆☆☆☆☆☆☆☆
积分:261
发帖:293
登录:2017/11/15
注册:2006/6/28
(3楼)较大文件上传的代码示例
该代码默认允许上传大小为30M,支持任意有后缀的文件。开发时测试上传处理时间为4秒左右。
► 相关附件:
· Upload.rar (1.91 Kb)


时间:2013年3月27日 8:00:23 IP:已记录 引用 回复

© Copyright 2006-2017,風雲工作室 All rights reserved.
湘ICP备05009306号QQ登录
操作 1 个库,连接 4 次,执行 9 次,耗时 281 毫秒。