1. 程式人生 > >Webclient 檔案非同步下載以及上傳,進度顯示

Webclient 檔案非同步下載以及上傳,進度顯示

客戶端檔案下載
public class DownloadTools
    {
        /// <summary>
        /// 下載實體
        /// </summary>
        private WebClient client;

        /// <summary>
        /// 檔案儲存路徑
        /// </summary>
        private string tempFilePath;

        /// <summary>
        /// 下載檔案的臨時檔名
        /// </summary>
        private string tempFileName;

        /// <summary>
        /// 下載進度條
        /// </summary>
        private ProgressBar pbDownload;

        /// <summary>
        /// 下載百分比
        /// </summary>
        private Label lbDownload;

        /// <summary>
        /// 建構函式
        /// </summary>
        public DownloadTools(ProgressBar pbDownload,Label lbDownload)
        {
            this.pbDownload = pbDownload;
            this.lbDownload = lbDownload;

            client = new WebClient();
            client.DownloadFileCompleted += Client_DownloadFileCompleted;
            client.DownloadProgressChanged += Client_DownloadProgressChanged;
        }

        /// <summary>
        /// 非同步下載
        /// </summary>
        /// <param name="serverPath">服務地址</param>
        /// <param name="webHeaderCollection">請求頭部資訊</param>
        public void DownloadFileAsync(string serverPath)
        {
            FolderBrowserDialog folder = new FolderBrowserDialog();
            folder.Description = "選擇檔案存放目錄";
            if (folder.ShowDialog() == DialogResult.OK)
            {
                tempFilePath = folder.SelectedPath;

                if (!Directory.Exists(tempFilePath))
                {
                    MessageBox.Show(tempFilePath + " 檔案路徑或部分路徑不存在");
                    return;
                }

                Uri serverUri = new Uri(serverPath);

                tempFileName = Guid.NewGuid().ToString() + ".temp";

                //下載路徑必須包含路徑和檔名
                string filePath = Path.Combine(tempFilePath, tempFileName);

                //client.Headers = webHeaderCollection;
                client.DownloadFileAsync(serverUri, filePath);
            }
        }

        /// <summary>
        /// 檔案下載進度顯示
        /// </summary>
        private void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            var responseHeaders = client.ResponseHeaders;

            int totalLength;
            if (responseHeaders != null)
            {
                bool isParseOk = int.TryParse(responseHeaders["ContentLength"], out totalLength);

                if (isParseOk)
                {
                    int Value = (int)e.BytesReceived;
                    pbDownload.Minimum = 0;
                    pbDownload.Maximum = totalLength;
                    pbDownload.Value = Value;
                    lbDownload.Text = totalLength == 0 ? "%" : ((int)(100.0 * Value / totalLength)).ToString() + "%";
                }
            }
        }

        /// <summary>
        /// 下載完成後,刪除臨時檔案,賦予伺服器上的檔名
        /// </summary>
        private void Client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            var responseHeaders = client.ResponseHeaders;

            string downloadFileName = HttpUtility.UrlDecode(responseHeaders["ContentFileName"]);

            if (responseHeaders["ContentError"] != null)
            {
                string error = HttpUtility.UrlDecode(responseHeaders["ContentError"]);
                MessageBox.Show(error);
                File.Delete(Path.Combine(tempFilePath, tempFileName));
            }
            else
            {
                if (e.Error != null)
                {
                    if (e.Error.InnerException != null)
                    {
                        MessageBox.Show(e.Error.InnerException.Message);
                    }
                    else
                    {
                        MessageBox.Show(e.Error.Message);
                    }
                }
                else
                {
                    //替換檔名字
                    string sourcePath = Path.Combine(tempFilePath, tempFileName);
                    string destPath = Path.Combine(tempFilePath, downloadFileName);
                    destPath = JudgeIsExist(destPath);
                    File.Move(sourcePath, destPath);
                    File.Delete(Path.Combine(tempFilePath, tempFileName));
                }
            }
        }

        /// <summary>
        /// 避免檔案重複
        /// </summary>
        private string JudgeIsExist(string path)
        {
            if (File.Exists(path))
            {
                string extension = Path.GetExtension(path);
                string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
                path = Path.Combine(tempFilePath, fileNameWithoutExtension + "-副本" + extension);
                return JudgeIsExist(path);
            }
            else
            {
                return path;
            }
        }
    }
客戶端檔案上傳
public class UploadTools
    {
        /// <summary>
        /// 下載實體
        /// </summary>
        private WebClient client;

        /// <summary>
        /// 上傳進度條
        /// </summary>
        private ProgressBar pbUpload;

        /// <summary>
        /// 上傳百分比
        /// </summary>
        private Label lbUpload;

        /// <summary>
        /// 建構函式
        /// </summary>
        public UploadTools(ProgressBar pbUpload, Label lbUpload)
        {
            this.pbUpload = pbUpload;
            this.lbUpload = lbUpload;

            client = new WebClient();
            client.UploadProgressChanged += Client_UploadProgressChanged;
            client.UploadFileCompleted += Client_UploadFileCompleted;
        }

        /// <summary>
        /// 非同步上傳
        /// </summary>
        /// <param name="serverPath">服務地址</param>
        /// <param name="webHeaderCollection">請求頭</param>
        public void UploadFileAsync(string serverPath)
        {
            OpenFileDialog fileDialog = new OpenFileDialog();
            fileDialog.Multiselect = false;
            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                string filePath = fileDialog.FileName;
                if (!string.IsNullOrEmpty(filePath))
                {
                    //副檔名
                    string extension = Path.GetExtension(filePath);
                    //檔名
                    string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath);
                    //帶副檔名的檔名
                    string fileName = Path.GetFileName(filePath);
                    //client.Headers = webHeaderCollection;
                    client.UploadFileAsync(new Uri(serverPath), filePath);
                }
            }
        }

        /// <summary>
        /// 上傳完畢
        /// </summary>
        private void Client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
        {
            var responseHeaders = client.ResponseHeaders;
            if (responseHeaders != null && responseHeaders["ContentError"] != null)
            {
                string error = HttpUtility.UrlDecode(responseHeaders["ContentError"]);
                MessageBox.Show(error);
            }
            else
            {
                if (e.Error != null)
                {
                    if (e.Error.InnerException != null)
                    {
                        MessageBox.Show(e.Error.InnerException.Message);
                    }
                    else
                    {
                        MessageBox.Show(e.Error.Message);
                    }
                }
            }
        }

        /// <summary>
        /// 上傳進度
        /// </summary>
        private void Client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
        {
            pbUpload.Minimum = 0;
            pbUpload.Maximum = (int)e.TotalBytesToSend;
            pbUpload.Value = (int)e.BytesSent;
            lbUpload.Text = e.ProgressPercentage.ToString();
        }
    }

呼叫例子
/// <summary>
        /// 上傳檔案
        /// </summary>
        private void BtnUpload_Click(object sender, EventArgs e)
        {
            //構造請求頭資訊
            //WebHeaderCollection webHeaderCollection = new WebHeaderCollection();
            //webHeaderCollection.Add("FunctionType", "ModelFileRelated");
            //webHeaderCollection.Add("RequestType", "Upload");
            //webHeaderCollection.Add("ProjectId", "");
            //webHeaderCollection.Add("FileType", HttpUtility.UrlEncode(""));
            //webHeaderCollection.Add("FileRemarks", HttpUtility.UrlEncode(""));
            //webHeaderCollection.Add("ModelId", "");
            string allParams = "?FunctionType=Upload";
            allParams += "&";
            allParams += "&FileType=" + HttpUtility.UrlEncode("");
            allParams += "&FileRemarks=" + HttpUtility.UrlEncode("");
            allParams += "&ModelId=";

            new UploadTools(pbUpload, lbUpload).UploadFileAsync("ModelFileUploadAndDownload.ashx" + allParams);
        }

        /// <summary>
        /// 點選檔案下載
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnDownload_Click(object sender, EventArgs e)
        {
            //構造請求頭資訊
            //WebHeaderCollection webHeaderCollection = new WebHeaderCollection();
            //webHeaderCollection.Add("FunctionType", "");
            //webHeaderCollection.Add("RequestType", "");
            //webHeaderCollection.Add("FileGuid", "");
            string allParams = "?FunctionType=Download";
            allParams += "&";
            new DownloadTools(pbDownload,lbDownload).DownloadFileAsync("ModelFileUploadAndDownload.ashx" + allParams);
        }

服務端IHttpHandler
public class ModelFileDownload : IHttpHandler
    {
        /// <summary>
        /// 資料庫實體
        /// </summary>
        private FileImageEntities fileInfoSqlServer = new FileImageEntities();

        /// <summary>
        /// 檔案儲存目錄
        /// </summary>
        private string fileSaveDirectory = ConfigurationManager.AppSettings["modelFileSavePath"];

        public void ProcessRequest(HttpContext context)
        {
            NameValueCollection allParams = context.Request.Params;
            string functionType = allParams["FunctionType"];
            if (!string.IsNullOrEmpty(functionType))
            {
                if (functionType.Equals("Upload"))
                {
                    //如果上傳檔案 
                    SaveFileFromClient(context);
                }
                else if (functionType.Equals("Download"))
                {
                    //如果下載檔案
                    PrepareForResponse(context);
                }
            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// 響應前資料準備
        /// </summary>
        /// <param name="guid"></param>
        private void PrepareForResponse(HttpContext context)
        {
            string fileGuid = context.Request.Params["FileGuid"];
            if (!string.IsNullOrEmpty(fileGuid))
            {
                //查詢資料庫中儲存的檔案路徑
                var fileInfo //檔案儲存資訊
                if (fileInfo != null && fileInfo.FilePath != null && fileInfo.FileName != null && fileInfo.FileExtension != null)
                {
                    ResponseFile(@fileInfo.FilePath, fileInfo.FileName + fileInfo.FileExtension);
                }
                else
                {
                    ErrorResponse("檔案不存在");
                }
            }
            else
            {
                ErrorResponse("檔案不存在");
            }
        }

        /// <summary>
        /// 根據檔案路徑下載指定檔案
        /// </summary>
        public void ResponseFile(string filepath, string filename)
        {
            Stream iStream = null;
            byte[] buffer = new Byte[1024 * 10];
            int length;
            long dataToRead;
            if (System.IO.File.Exists(filepath))
            {
                iStream = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

                dataToRead = iStream.Length;

                HttpContext.Current.Response.ContentType = "application/octet-stream";//直接用連結再網頁上下載
                HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(filename));
      //自定義欄位
                HttpContext.Current.Response.AddHeader("ContentFileName", HttpUtility.UrlEncode(filename));
                HttpContext.Current.Response.AppendHeader("ContentLength", dataToRead.ToString());
                while (dataToRead > 0)
                {
                    if (HttpContext.Current.Response.IsClientConnected)
                    {
                        length = iStream.Read(buffer, 0, buffer.Length);
                        HttpContext.Current.Response.OutputStream.Write(buffer, 0, length);
                        HttpContext.Current.Response.Flush();
                        dataToRead = dataToRead - length;
                    }
                    else
                    {
                        dataToRead = -1;
                    }
                }
                if (iStream != null) iStream.Close();
                HttpContext.Current.Response.End();
            }
            else
            {
                ErrorResponse("檔案不存在");
            }
        }

        /// <summary>
        /// 儲存檔案到伺服器
        /// </summary>
        public void SaveFileFromClient(HttpContext context)
        {
            NameValueCollection allParams = context.Request.Params;
            string projectId = allParams["ProjectId"];
            string modelId = allParams["ModelId"];
            string fileType = HttpUtility.UrlDecode(allParams["FileType"]);
            string fileRemarks = allParams["FileRemarks"] == null ? null : HttpUtility.UrlDecode(allParams["FileRemarks"]);
            string dateTime = DateTime.Now.ToString("yy-MM-dd");

            HttpFileCollection files = context.Request.Files;
            if (files != null && files.Count > 0)
            {

                #region 檔案儲存路徑
                string fileNameWithExtension = files[0].FileName;
                string fileNameWithOutExtension = Path.GetFileNameWithoutExtension(fileNameWithExtension);
                string extension = Path.GetExtension(fileNameWithExtension);

                string newFileSaveAbsolutePath = fileSaveDirectory + @"\" + dateTime;

                if (!Directory.Exists(newFileSaveAbsolutePath))
                {
                    Directory.CreateDirectory(newFileSaveAbsolutePath);
                }

                //判斷檔案路徑是否已存在
                string fileGuid = JudgeIsExist(newFileSaveAbsolutePath, extension);

                string fileSaveAbsolutePath = Path.Combine(newFileSaveAbsolutePath, fileGuid + extension);
                #endregion

                files[0].SaveAs(fileSaveAbsolutePath);//儲存檔案
            }
        }

        /// <summary>
        /// 錯誤返回 ContentError
        /// </summary>
        private static void ErrorResponse(string error)
        {
            HttpContext.Current.Response.AddHeader("ContentError", HttpUtility.UrlEncode(error));
            HttpContext.Current.Response.End();
        }

        /// <summary>
        /// 判斷檔案儲存路徑是否已存在
        /// </summary>
        /// <returns>fileGuid</returns>
        private string JudgeIsExist(string newFileSaveAbsolutePath,string extension)
        {
            string fileGuid = Guid.NewGuid().ToString();
            string fileSaveAbsolutePath = Path.Combine(newFileSaveAbsolutePath, fileGuid + extension);
            if (!System.IO.File.Exists(fileSaveAbsolutePath))
            {
                return fileGuid;
            }
            else
            {
                return JudgeIsExist(newFileSaveAbsolutePath, extension);
            }
        }
    }