65.9K
CodeProject 正在变化。 阅读更多。
Home

使用经典ASP.NET和C#实现带进度条的多文件上传

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (8投票s)

2010年9月1日

CPOL

4分钟阅读

viewsIcon

108470

downloadIcon

6742

在 Web 应用程序中,上传文件时显示进度条是很有必要的。本文将帮助您在 ASP.NET 2.0 中为单文件和多文件上传创建进度条。

引言

本文为读者提供了一个关于如何在基于 Web 的应用程序中创建单文件/多文件上传进度条的良好思路。我们之前的一个项目要求显示一个连续的进度条以及上传百分比。本文将为您提供关于如何使用 ASP.NET 2.0 和 .NET Framework 2.0 创建此类控件的宝贵信息。此外,由于该解决方案使用了 IFrame 来加载文件上传控件,因此部署该控件的页面不会发生回发。用户可以在上传过程中自由访问页面的其他部分。

背景

我的初步想法是,在服务器端计算进度量,并使用 JavaScript 定时函数通过 XMLHttpRequest 对象读取服务器端的进度量,从而从客户端更新进度条。但这效果不佳,因为它要么显示 0%,要么显示完整的 100%,但不是连续的进度。我使用了 Mozilla Firebug 来追踪 XMLHttpRequest 对象的请求模式。出于某种原因,XMLHttpRequest 会被排队,直到服务器端事件处理程序完成其执行,在这种情况下是上传完成,所以它要么在服务器端上传开始之前发出请求,要么在服务器端上传完成后发出请求。因此,进度条要么显示 0% 或 100%。

我想感谢 Mr. Munur Shaik:http://www.c-sharpcorner.com/UploadFile/munnamax/ProgressBar07062007122251PM/ProgressBar.aspx 的创意,我已将其用于创建我的进度条。此外,我想向我们的架构师 Anil Sistla 表示感谢,感谢他对我的支持,使我得以完成此解决方案。我希望本文能为正在寻找类似解决方案的人节省大量时间。

使用代码

下面是源代码结构。UploadProgressBar.ascx 文件是用户控件,它显示一个带有“添加/移除”按钮的单文件上传控件。“添加”按钮会添加多个文件上传控件,“移除”按钮则一次移除一个文件上传控件。

CodeStructure.jpg

下图显示了初始文件上传屏幕。FileUploadIframe.aspx 包含一个简单的 HTML IFrame 标签,用于加载控件页面(FileUpload.aspx)。这里使用 IFrame 是因为放置多文件上传控件的主页面在按下上传按钮时,不应该发生回发。

FileUploadControlUi.jpg

文件上传过程中,进度条显示如下:

MultiFileUploadProgressBar.jpg

以下是创建进度条的代码:

public void CreateProgress(HttpFileCollection fileCollection)
{
    //string fileName, int id, string progressAmount
    StringBuilder sbProgress = new StringBuilder();
    sbProgress.Append("<html><head><LINK REL=StyleSheet " + 
      "HREF='StyleSheet1.css' TYPE='text/css' /></head>  <body>");
    sbProgress.Append("<script src='JScript1.js' type='text/javascript'>" + 
      "</script><table id='mainTable' border='1'>");
    for (int i = 0; i < fileCollection.Count; i++)
    {
        string strProgressBarId = "progressBar" + i;
        string strPercentageId = "percentage" + i;
        string fileName = fileCollection[i].FileName;
        sbProgress.Append("<tr><td><p>" + fileName + 
          "</p></td><td><div id='xxx' " + 
          "style='background-color:White; width: 100px;height:15px; " + 
          "border-color:Black;border-width:thin;border-style:solid'>");
        sbProgress.Append("<div class='progressBar'  id='" + 
          strProgressBarId + "' ></div></div></td>" + 
          "<td><p><div id='" + strPercentageId + 
          "'></div></p></td></tr>");
    }
    sbProgress.Append("</table>");
    for (int i = 0; i < fileCollection.Count; i++)
    {
        sbProgress.Append("<script type='text/javascript'> " + 
          "SetProgressBarProgressAmount(" + i + ",0 );</script>");
    }
    sbProgress.Append(PrepareTheGridHtml());
    sbProgress.Append("</body></html>");

    HttpContext.Current.Response.Write(sbProgress.ToString());
    HttpContext.Current.Response.Flush();
}

此方法 (CreateProgress()) 主要将进度条的 HTML 推送到输出流以创建一个空的进度条。在上面的代码中,SetProgressBarProgressAmount(..) 是一个 JavaScript 方法,它接受两个参数:第一个参数是进度条的 ID,如果显示多个进度条,则此 ID 很重要;第二个参数是进度量。随着文件下载到服务器,此进度条将根据下载百分比进行设置,最终在文件下载完成后,它将被设置为 100%。对于多文件上传,将显示多个进度条,每个文件一个,文件将逐个上传到服务器,并且我们可以看到每个文件的进度量。以下是将文件下载到服务器的代码:

public void DownloadTheFileToServer(HttpPostedFile file, int id)
{
    Stream stream = null;
    FileStream fs = null;

    #region File Download Code goes here
    try
    {
        string strFileName = System.IO.Path.GetFileName(file.FileName);
        int contentLength = file.ContentLength;
        stream = file.InputStream;
        long totalUploadSize = stream.Length;
        int bufferSize = 0;
        //less than 1kB
        if (totalUploadSize <= 1024)
        {
            bufferSize = 1024;
        }
        //less than 4kB but more than 1kB
        else if (bufferSize <= 4096)
        {
            bufferSize = 4096;
        }
        //less than 8Kb
        else if (bufferSize <=8192)
        {
            bufferSize = 8192;
        }
        else
        {
            bufferSize = 16384;
        }

        byte[] b = new byte[1024];
        int tripDownloadSize = 0;
        long totalDownloadedSize = 0;
        float Percentage = 0;
        bool isNewFile = true;
        string fileStoreLocation = 
          ConfigurationManager.AppSettings["FileStoreLocation"];
        fs = new FileStream(fileStoreLocation + strFileName, FileMode.Append);

        //Uplaods 8Kb at a time
        while ((tripDownloadSize = stream.Read(b, 0, 1024)) > 0)
        {
            fs.Write(b, 0, tripDownloadSize);
            totalDownloadedSize += tripDownloadSize;
            Percentage = (int)(totalDownloadedSize * 100) / totalUploadSize;
            setProgressBar(id, Percentage.ToString());
            System.Threading.Thread.Sleep(100);
            isNewFile = false;
        }

    }
    catch (Exception objException)
    {
        throw objException;
    }
    finally
    {
        if (stream != null)
        {
            stream.Close();
            stream.Dispose();
        }
        if (fs != null)
        {
            fs.Close();
            fs.Dispose();
        }
    }
    #endregion
}

在上述方法中,我根据文件大小编写了逻辑来决定流的缓冲区大小,但这完全取决于开发人员如何设置读取输入流的缓冲区大小(字节数组大小)。本文主要关注如何在文件下载过程中创建/更新进度。在上面的代码中,在 while 循环内,每次都会计算总下载大小,下载的百分比将通过以下公式确定:总下载大小 / 总文件大小 * 100。使用 setProgressBar(id, Percentage) 方法,我们可以为具有 id 的特定进度条设置进度。以下是 SetProgressBar 方法的代码:

public static void setProgressBar(int id, string progressAmount)
{
    StringBuilder sb = new StringBuilder();
    sb.Append("&lt;body&gt;&lt;script type='text/javascript'&gt;" +
       "SetProgressBarProgressAmount(" + id + ",'" + progressAmount + 
       "'); &lt;/script&gt;&lt;/body&gt;");
    HttpContext.Current.Response.Write(sb.ToString());
    HttpContext.Current.Response.Flush();
}

搜索 `appsettings` 下的 `FileStoreLocation` 条目,并在 `web.config` 文件中将其设置为您计算机上的本地文件夹位置;通过文件上传控件上传的文件将下载到此位置。

免责声明

本文为希望拥有类似进度条的用户提供了一个起点。此控件尚未准备好投入生产环境部署。此进度条控件并未考虑许多因素,例如可以上传到服务器的文件类型等。开发人员有责任确保其符合其需求。对于此控件造成的任何应用程序/产品损坏,我概不负责。我希望开发人员在将此解决方案集成/用于现有应用程序之前对其进行完整评估。

© . All rights reserved.