.netcore+vue 實現壓縮檔案下載

程式猿貝塔發表於2020-09-23

一.前言

目前接觸的專案中,給定的需求是將系統內所有使用者的資料整理好,並儲存到資料夾內,目的主要是防止使用者在實施人員已配置好的基礎上由於不熟悉系統,導致的誤刪或者誤操作。減少實施人員的配置工作。我首先想到的就是將資料匯入到Excel中,並以各個使用者的名稱命名資料夾做好分類。

vue下實現Excel匯入這個我們見的比較多了,當時我也確實實現了下載Excel的功能,但是後續發現儲存的檔案都在伺服器上,那就有一個問題了,實施人員是通過頁面點選的一鍵儲存按鈕,資料也確實儲存了,但是卻是在伺服器上,如果想實時看到資料呢,是不是還要去伺服器上拷貝一份下來。相對來講確實比較繁瑣,所以整理了下載壓縮檔案到本地的功能,一起看一下怎麼實現的吧。

1.1.net core 壓縮檔案

思路是在後臺將資料夾整體壓縮為zip格式的壓縮包,並返回檔案流到前端,然後前端接收檔案流實現瀏覽器下載的功能。

後端程式碼,將

        public async Task<FileStreamResult> DownloadFiles(DownLoadModel input)
        {
            if (!Directory.Exists(input.pathUrl))
            {
                throw new UserFriendlyException("當前要下載的資料夾不存在或已刪除");
            }
            var zipFileUrl = _configurationRoot["downLoadUrlConf:downloadZipFileUrl"];
            if (File.Exists(zipFileUrl))
            {
                File.Delete(zipFileUrl);
            }
            ZipHelper.CreateZip(input.pathUrl, zipFileUrl);
            var memoryStream = new MemoryStream();
            using (var stream = new FileStream(zipFileUrl, FileMode.Open))
            {
                await stream.CopyToAsync(memoryStream);
            }
            memoryStream.Seek(0, SeekOrigin.Begin);
            return new FileStreamResult(memoryStream, "application/octet-stream");//檔案流方式,指定檔案流對應的ContenType。
        }
    public static class ZipHelper
    {
        /// <summary>
        /// 壓縮檔案
        /// </summary>
        /// <param name="sourceFilePath"></param>
        /// <param name="destinationZipFilePath"></param>
        public static void CreateZip(string sourceFilePath, string destinationZipFilePath)
        {
            if (sourceFilePath[sourceFilePath.Length - 1] != System.IO.Path.DirectorySeparatorChar)
                sourceFilePath += System.IO.Path.DirectorySeparatorChar;

            ZipOutputStream zipStream = new ZipOutputStream(File.Create(destinationZipFilePath));
            zipStream.SetLevel(6);  // 壓縮級別 0-9
            CreateZipFiles(sourceFilePath, zipStream, sourceFilePath);

            zipStream.Finish();
            zipStream.Close();
        }
        /// <summary>
        /// 遞迴壓縮檔案
        /// </summary>
        /// <param name="sourceFilePath">待壓縮的檔案或資料夾路徑</param>
        /// <param name="zipStream">
        /// <param name="staticFile"></param>
        private static void CreateZipFiles(string sourceFilePath, ZipOutputStream zipStream, string staticFile)
        {
            Crc32 crc = new Crc32();
            string[] filesArray = Directory.GetFileSystemEntries(sourceFilePath);
            foreach (string file in filesArray)
            {
                if (Directory.Exists(file))                     //如果當前是資料夾,遞迴
                {
                    CreateZipFiles(file, zipStream, staticFile);
                }

                else                                            //如果是檔案,開始壓縮
                {
                    FileStream fileStream = File.OpenRead(file);

                    byte[] buffer = new byte[fileStream.Length];
                    fileStream.Read(buffer, 0, buffer.Length);
                    string tempFile = file.Substring(staticFile.LastIndexOf("\\") + 1);
                    ZipEntry entry = new ZipEntry(tempFile);

                    entry.DateTime = DateTime.Now;
                    entry.Size = fileStream.Length;
                    fileStream.Close();
                    crc.Reset();
                    crc.Update(buffer);
                    entry.Crc = crc.Value;
                    zipStream.PutNextEntry(entry);

                    zipStream.Write(buffer, 0, buffer.Length);
                }
            }
        }
    }

其中CreateZip方法傳入一個原始檔的路徑,一個目標檔案的路徑,這裡我的目標檔案設定在appsetting.json裡是個臨時路徑,只為前端當次下載使用。這樣我們就在後臺將資料以壓縮包的形式壓縮好,並返回資料流給前端了。

1.2 vue 下載壓縮檔案

      <el-button
          icon="el-icon-download"
          size="mini"
          type="primary"
          class="pull-right"
          @click="downloadFile"
        >下載檔案到本地</el-button>
 downloadFile() {
       this.loading = true;
       let postData = { pathUrl: this.filePathMag };
       AjaxHelper.post(this.downLoadUrl, postData, {
         responseType: "blob",
       }).then((res) => {
         // 處理返回的檔案流
         const content = res.data;
         const blob = new Blob([content], { type: "application/zip" });
         const fileName = this.tenant.name + "配置資訊.zip";
         if ("download" in document.createElement("a")) {
           // 非IE下載
           const elink = document.createElement("a");
           elink.download = fileName;
           elink.style.display = "none";
           elink.href = URL.createObjectURL(blob);
           document.body.appendChild(elink);
           elink.click();
           URL.revokeObjectURL(elink.href); // 釋放URL 物件
           document.body.removeChild(elink);
         } else {
           // IE10+下載
           navigator.msSaveBlob(blob, fileName);
         }
         this.loading = false;
       });
     },

之前下載Excel時,我們傳入後端的content-type為"application/json;application/octet-stream",經過測試發現壓縮檔案不能使用這種content-type,所以我們去掉了。
另外就是const blob = new Blob([content], { type: "application/zip" });這行程式碼,如果不加,雖然也能下載,但是下載後的壓縮包卻無法開啟,提示壓縮不正確或壓縮包已損壞。

好了,到此壓縮檔案的下載就完成了,由於我也是第一次遇到壓縮檔案的下載,經過摸索終於解決了問題。看起來也比較簡單,你學會使用了嗎?

相關文章