asp.net 文件分片上傳


 

  最近在研究文件上傳,里面的門道還是挺多的,網上大多數文章比較雜亂,代碼都是片段,對於新手小白來說難度較高,所以在此詳細寫一下今天看到的一個demo,關於文件分片上傳的。

  

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha384-xBuQ/xzmlsLoJpyjoggmTEz8OWUFM0/RC5BsqQBDX2v5cMvDHcMakNTNrHIW2I5f" crossorigin="anonymous"></script>
</head>
<body>
    <input type="file" id="file6" multiple><button type="button" class="btnFile6">分片上傳</button><div class="result"></div>
</body>
</html>
<script>
    $(".btnFile6").click(function () {
        var upload = function (file, skip) {
            var formData = new FormData();//初始化一個FormData對象
            var blockSize = 1000000;//每塊的大小
            var nextSize = Math.min((skip + 1) * blockSize, file.size);//讀取到結束位置
            var fileData = file.slice(skip * blockSize, nextSize);//截取 部分文件 塊
            formData.append("file", fileData);//將 部分文件 塞入FormData
            formData.append("fileName", file.name);//保存文件名字
            $.ajax({
                url: "Handler.ashx",
                type: "POST",
                data: formData,
                processData: false,  // 告訴jQuery不要去處理發送的數據
                contentType: false,   // 告訴jQuery不要去設置Content-Type請求頭
                success: function (responseText) {
                    $(".result").html("已經上傳了" + (skip + 1) + "塊文件");
                    if (file.size <= nextSize) {//如果上傳完成,則跳出繼續上傳
                        alert("上傳完成");
                        return;
                    }
                    upload(file, ++skip);//遞歸調用
                }
            });
        };
        var file = $("#file6")[0].files[0];
        upload(file, 0);
    });
</script>

  后端一般處理程序:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;

namespace WebApplication1
{
    /// <summary>
    /// Handler 的摘要說明
    /// </summary>
    public class Handler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            //保存文件到指定目錄
            var filePath = @"D:\penglong\study\WebApplication1\WebApplication1\uploads\" + context.Request.Form["fileName"];
            //創建一個追加(FileMode.Append)方式的文件流
            using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write))
            {
                using (BinaryWriter bw = new BinaryWriter(fs))
                {
                    //讀取文件流
                    BinaryReader br = new BinaryReader(context.Request.Files[0].InputStream);
                    //將文件留轉成字節數組
                    byte[] bytes = br.ReadBytes((int)context.Request.Files[0].InputStream.Length);
                    //將字節數組追加到文件
                    bw.Write(bytes);
                }
            }
        }
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

  瀏覽器監聽的請求過程如圖:

  

  目前代碼里設置的是1M一片,2.25MB的文件被分為了3片,因此請求的時候請求了三次,這樣,我們就可以上傳大文件了。(webconfig可以設置最大文件為2G,當上傳的文件超過2G或者我們不希望更改webconfig配置時,則可以使用這個進行分片上傳,網上大多數分片插件的原理也是如此,通過構造formdata對象進行多次上傳,然后在后端進行文件的合並操作)。

 

  參考鏈接:https://www.cnblogs.com/fjzhang/p/7227401.html?utm_source=itdadao&utm_medium=referral


  補:

  從demo上講,上面的案例基本沒有問題,但是實際使用的場景中,會存在這樣一個問題,由於文件是存在磁盤上的,當用戶再次上傳同名文件時,文件流會被繼續追加到這個文件里,而不是另起一個文件,或者做覆蓋操作,因為FileMode.Append模式下會檢測當前路徑是否存在這個文件,存在則append。

  那么該如何解決這個問題呢,一開始我想到的是通過size判斷,如果傳入文件的size,不等於讀取到的文件流對象的大小,則說明文件還沒有傳輸完畢,則可以繼續append。但是當等於時,是需要新建文件的,所以就得重命名了,windows系統再重命名的時候會在原有文件名后面帶上副本啊之類的名稱,我這里為了簡潔,直接在前端讀取了一個系統時間作為唯一標識,來混入文件名,這樣后台保存的文件就不會存在文件流並入一個文件的問題了。

     代碼如圖:

  

  

  這里有一點需要注意,為什么我不在后端去生成這個時間標識,而是在前端生成呢?原因是這里是進行分片上傳的,會多次請求后端接口,如果在后端生成唯一標識,那么在上傳文件的方法里會生成多個文件,這樣是不對的,所以這里在前端做了參數取值,每次點擊的時候生成一個唯一標識,即便分N次上傳,名稱也是同一個,文件流就能正常合並在一個文件里了。

  當然,關於這個同名文件上傳改名的操作,后端應該也能完成,但是感覺過於復雜,這里就沒有嘗試。有興趣的園友可以一起探討思路。暫時就補充到這里了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM