对于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支持)来获取当前上传的进度信息,并实时反映到上传页面上。
progressInfo.asp
<%@language=vbscript enablesessionstate=false lcid=1033%>
<%
Response.CacheControl = "no-cache"
Response.Expires = -1
Application.Lock
If Application("count") >= 100 Then Application("count") = 0
Application("count") = Application("count") + 1
Application.UnLock
%>
var pb = new progressBar();
pb.setSize(100,<%=Application("count")%>);
progressInfo.htm
<script src="xmlLib.js"></script>
<style>
.progressBar{
width: 250px;
height: 15px;
}
.progressInfo{
width: 250px;
height: 15px;
border: 1px solid #000000;
overflow: hidden;
text-align: center;
font-size: 9pt;
padding-top: 1;
position: absolute;
}
.progress{
background-color: #5FFF3F;
width: 0%;
height: 15px;
overflow: hidden;
}
</style>
<script>
var r = "传输: {0}K 还未完成";
var s = "您的文件已经上传完成";
function progressBar()
{
this.totalSize = 100;
this.sizeCompleted = 0;
this.percentDone = "0%";
this.setSize = function(totalSize, size)
{
var oProgress = document.getElementById("progress");
var oProgressInfo = document.getElementById("progressInfo");
if (oProgress == null || oProgressInfo == null)
return;
if (totalSize <= 0)
return;
this.totalSize = totalSize;
this.sizeCompleted = size;
if (size < 0)
this.sizeCompleted = 0;
else if (size > this.totalSize)
this.sizeCompleted = this.totalSize;
var sizeLeft = 0;
var progressInfoText = "";
sizeLeft = this.totalSize - this.sizeCompleted;
this.percentDone = Math.round(size / this.totalSize * 100) + "%";
oProgress.style.width = this.percentDone;
if (sizeLeft > 0)
progressInfoText = r.replace("{0}", sizeLeft);
else
progressInfoText = s;
oProgressInfo.innerHTML = progressInfoText;
}
}
</script>
<div id="progressBar" class="progressBar">
<div class="progressInfo" id="progressInfo" onselectstart="return false;">
</div>
<div class="progress" id="progress">
</div>
</div>
<script language="JavaScript" type="text/javascript">
<!--
var iTimerID = null;
var xmlHttp = XmlHttpPool.pick();
LoadProgressInfo();
function LoadProgressInfo()
{
var url = "progressInfo.asp"
try
{
xmlHttp.open("GET", url, true);
xmlHttp.send(null);
xmlHttp.onreadystatechange = function()
{
LoadData(xmlHttp);
}
}
catch(e)
{
alert(e)
}
}
function LoadData(xmlhttp)
{
if (xmlhttp.readyState == 4)
{
iTimerID = window.setTimeout("LoadProgressInfo()", 100);
eval(xmlhttp.responseText);
}
}
//-->
</script>
xmlLib.js
//////////////////
// Helper Funcs //
//////////////////
// used to find the Automation object name
function getDomDocumentPrefix() {
if (getDomDocumentPrefix.prefix)
return getDomDocumentPrefix.prefix;
var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
var o;
for (var i = 0; i < prefixes.length; i++) {
try {
// try to create the objects
o = new ActiveXObject(prefixes[i] + ".DomDocument");
return getDomDocumentPrefix.prefix = prefixes[i];
}
catch (ex) {};
}
throw new Error("Could not find an installed XML parser");
}
function getXmlHttpPrefix() {
if (getXmlHttpPrefix.prefix)
return getXmlHttpPrefix.prefix;
var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
var o;
for (var i = 0; i < prefixes.length; i++) {
try {
// try to create the objects
o = new ActiveXObject(prefixes[i] + ".XmlHttp");
return getXmlHttpPrefix.prefix = prefixes[i];
}
catch (ex) {};
}
throw new Error("Could not find an installed XMLHttp object");
}
//////////////////////////
// Start the Real Funcs //
//////////////////////////
// XmlHttp factory
function XmlHttp() {}
XmlHttp.create = function () {
try {
// NS & MOZ
if (window.XMLHttpRequest) {
var req = new XMLHttpRequest();
// some versions of Moz do not support the readyState property
// and the onreadystate event so we patch it!
if (req.readyState == null) {
req.readyState = 1;
req.addEventListener("load", function () {
req.readyState = 4;
if (typeof req.onreadystatechange == "function")
req.onreadystatechange();
}, false);
}
return req;
}
// IE
if (window.ActiveXObject) {
return new ActiveXObject(getXmlHttpPrefix() + ".XmlHttp");
}
}
catch (ex) {}
// Fail
throw new Error("Your browser does not support XmlHttp objects");
};
// XmlDocument factory
function XmlDocument() {}
XmlDocument.create = function () {
try {
// DOM2, MOZ & NS
if (document.implementation && document.implementation.createDocument) {
var doc = docume