ASP.NET MVC 4 批量上傳文件


上傳文件的經典寫法:

<form id="uploadform" action="/Home/UploadFile" method="post" enctype="multipart/form-data">
    <input type="file" name="uploadfile" />
    <input type="submit" value="上傳" />
</form>

這里的表單form里只有1個file,所以也就只能一次上傳一個文件。如果需要上傳的文件很多,希望在打開瀏覽文件窗口后可以用鼠標框選或按着鍵盤的ctrl鍵用鼠標去點選,該怎么辦呢?

第一種方法——有幾個file就在form里寫幾個file:

<input type="file" name="uploadfile" />
<input type="file" name="uploadfile" />
<input type="file" name="uploadfile" />
<input type="file" name="uploadfile" />
<input type="file" name="uploadfile" />
......

Oh my god !

如果有20個文件要上傳的話就寫20個<input type="file" name="uploadfile" />?不可以!

第二種方法——用jquery克隆文件

這樣form里還是只寫一個file,然后用jquey去動態添加。效果如圖:

<form id="uploadform" action="/Home/UploadFile" method="post" enctype="multipart/form-data">
當前有<span id="inputNum">1</span>個文本框,已選擇<label id="fileNum">0</label>個文件。
  <div id="upload">
      <input type="file" name="uploadfile" style="border: 1px solid gray; width: 500px;" />
  </div>
  <input type="submit" value="上傳" />
</form>
<div id="status"></div>

我們想在文本框后面加一個“添加”、“刪除“的鏈接,點擊后增加一個文件框或刪除。

既然這個input file是動態添加的,那么后面跟着的“取消”、”增加”也是跟着一起創建的。本以為很難,結果用jquery反而很簡單的:

$("input[type=file]").after(
            //" <a href='#' class='clear-inputfile'>清除內容</a>" + " | " +
            " <a href='#' class='removeInputFile'>取消</a>    " + " | " +
            " <a href='#' class='addInputFile'>增加</a>"
 );

先用input[type=file]找到這個inputy,然后在他的后面(after)加上超鏈接(a),就這么簡單!

Jquery:

//增加多個文本框 (復制當前行)         
        $('.addInputFile').click(function () {
            var clone = $(this).parent().clone(true);//true:連事件一起復制
            var file = clone.children("input[type=file]").val(null);
            $(clone).insertAfter($(this).parent());
        });

clone() 方法

定義和用法

clone() 方法生成被選元素的副本,包含子節點、文本和屬性。

語法

$(selector).clone(includeEvents)

這里把事件一起復制了,所以是:

var clone = $(this).parent().clone(true);

注意我們復制的是<div id="upload">。

如果已經選擇了文件,克隆后會把文件框里的內容一起復制過來,所以在val()中加上null清除內容:

var file = clone.children("input[type=file]").val(null);

增加后也要有取消,當取消到只剩一個的時候給個提示。

//刪除            
        $('.removeInputFile').click(function () {
            var num = $('#upload input[type=file]').length;
            if (num == 1) {
                alert('必須保留一個!');
                return false;
            }
            $(this.parentElement).remove();
        });

動態添加文件操作完畢!

上傳文件后如果刷新瀏覽器會再次提交,這個問題很普遍,一不注意就重復提交了。所以這里采用ajax的方式上傳文件!用mvc的Ajax.BeginForm嗎?這個就是異步的啊!但是如果不配合一個插件來的話,單靠Ajax.BeginForm還是不能完成異步上傳文件並且避免刷新重復提交!!這個插件就是jquery.form.js

$('form').ajaxForm({
            dataType: "html",//json也可以,以避免FF里此錯誤:HierarchyRequestError: Node cannot be inserted at the specified point in the hierarchy
            ///判斷是否有文件 formData不支持IE!
            ///formData is an array of objects 
            ///representing the name and value of each field that will be sent to the server;
            beforeSubmit: function (formData) {
                //沒有選擇文件則退出
                if (selectedFileNum() == 0) {
                    alert("請選擇文件!");
                    return false;
                }
            },
            success: function (responseText) {//responseText:后台傳來的string                            
                status.html(responseText);
            },
            error: function (xhr, textStatus, errorThrown) {//在前端擋住請求
                alert('文檔上傳錯誤.' + xhr.responseText);//例如文件過大等錯誤
                status.html(xhr.responseText);
            },
            complete: function (xhr) {
                status.html(xhr.responseText);
                $("form").resetForm();//重置表單
            }
        });//end jquey.form

Ajax.BeginForm也要配合jquery.form.plugin一起使用

Ajax.BeginForm的寫法:

@using (Ajax.BeginForm(
                        "UploadFile", 
                        "Home",
                        new AjaxOptions
                        {
                            UpdateTargetId = "status",
                            HttpMethod = "Post"
                        }, 
                        new { enctype = "multipart/form-data" }
                        )
        )
{
    <div id="upload">
        <input type="file" name="uploadfile" style="border: 1px solid gray;" />
    </div>
    <input type="submit" value="上傳" />
}

目前都是前端的操作,接下來看后台的保存文件到服務器是怎么做的。

Controller:

//上傳文件
        [HttpGet]
        public ActionResult UploadFile() { return View(); }
        [HttpPost]
        public ActionResult UploadFile(IEnumerable<HttpPostedFileBase> uploadfile)
        {
            foreach (var file in uploadfile)
            {
                if (file != null && file.ContentLength > 0)
                {
                    var fileName = Path.GetFileName(file.FileName);
                    var path = Path.Combine(Server.MapPath("~/Uploads"), fileName);
                    //如遇相同文件則先刪除再保存
                    if (System.IO.File.Exists(path))
                        System.IO.File.Delete(path);
                    file.SaveAs(path);
                }
            }
           return Content("上傳完畢!");
        } 

因為上傳的是多個文件,所以這里要用IEnumerable<HttpPostedFileBase>類型。使用HttpPostedFileBase來接收傳遞的文件是ASP.NET MVC的推薦做法,不推薦用Request。要注意HttpPostedFileBase類型的參數uploadfile這個名稱要和前端form里的input的name保持一致!

第三種方法——使用jquery上傳插件

上面說那么多,其實這個才是主角。

要想一次性在瀏覽窗口中選中多個文件同時上傳到服務器,還是要用個插件才方便。尋覓很久還是發現uploadify最合心意,其他的也很優秀,但是在IE瀏覽器里無法一次多選,只能是點一次選一個點一次選一個,然后一起上傳。

uploadify常用的一些設置:

$(document).ready(function () {
        $("#myUploadFile").uploadify({
            //屬性
            'auto': true, //自動上傳
            'height': 30, //按鈕的高度
            'width': 80, //按鈕的寬度
            'swf': '../Scripts/Uploadify/uploadify.swf', //必輸入!flash.注意路徑!!
            'fileObjName': 'uploadfile', //傳遞給后台程序的參數, 否則會接收不到!
            'uploader': '../Home/Uploadify', //后台處理程序. 注意路徑!!
            'queueID': 'queue', //顯示上傳隊列的容器
            'buttonText': '選擇文件', //按鈕顯示文字
            //'fileSizeLimit': '5MB',
            //'queueSizeLimit': 5, //同時允許上傳5個文件
            'fileTypeExts': '*.xls;*.xlsx',
            'removeCompleted': false, //上傳后保持隊列不消失
            'requeueErrors': true,
            //事件
            'onSelect': function (file)//從瀏覽窗口中選擇文件
            {
                if (file.size / 1024 / 1024 > 10) //文件10M
                {
                    alert('文件過大,請分批上傳!');
                    $('#myUploadFile').uploadify('cancel', file.id); //cancel方法可以帶上file的id作為參數,指定取消該項。
                }
            },
            'onCancel': function (file)//從隊列中取消文件 
            {
                //alert('文件: ' + file.name + ' 被取消.');
                //document.getElementById("fileCount").value -= 1;
            },
            'onClearQueue': function (queueItemCount) {//只在未上傳前有效,上傳后其實還保存在隊列中。
                //alert(queueItemCount + ' file(s) were removed from the queue');
            },
            'onDialogClose': function (queueData) //當瀏覽窗口關閉時
            {
                //alert(queueData.filesQueued + ' files were queued of ' + queueData.filesSelected + ' selected files. There are ' + queueData.queueLength + ' total files in the queue.');
                //document.getElementById("fileCount").value = queueData.queueLength; //隊列中文件數量
                //document.getElementById("lblStatus").innerText = "";
            },
            'onQueueComplete': function (queueData)//全部上傳完畢后觸發
            {
                //alert(queueData.uploadsSuccessful + ' 個文件成功上傳。上傳后請點擊“提交”。');
                //document.getElementById("fileCount").value = "";
                //window.location.href = "Default.aspx"//重加載頁面
                // window.location.reload(); //
                //alert("reload");
                //alert("upload Done");
            },
            'onUploadError': function (file, errorCode, errorMsg, errorString) {
                alert('The file ' + file.name + ' 上傳失敗: ' + errorString);
                //alert('errorCode:'+errorCode);
                //alert('errormsg:' + errorMsg);//500
                //alert('errorString:' + errorString);//HTTP Error (500)
            },
            'onUploadSuccess': function (file, data, response) {
                //alert('The file ' + file.name + ' 上傳成功!');
                //alert('data is :' + data);//data是controller傳來的str
                $('#msg').text(data);
                //alert('response is :' + response); //response is true
            },
            'onSelectError': function (file, errorCode, errorMsg) //錯誤信息
            {
                switch (errorCode) {
                    case -100:
                        alert("上傳的文件數量已超過系統限制的" + $('#myUploadFile').uploadify('settings', 'queueSizeLimit') + "個文件");
                        break;
                    case -110:
                        alert("文件(" + file.name + ")大小超出系統限制的" + $('#myUploadFile').uploadify('settings', 'fileSizeLimit') + "大小!");
                        break;
                    case -120:
                        alert("文件(" + file.name + ")大小異常!");
                        break;
                    case -130:
                        alert("文件(" + file.name + ")類型不正確!");
                        break;
                }
            }
        });
    });

<input type="file" id="myUploadFile" />
<p id="queue"></p>

Controller:

     [HttpGet]
        public ActionResult Uploadify() { return View(); }
        [HttpPost]
      public ActionResult Uploadify(HttpPostedFileBase uploadfile)
        {
            if (uploadfile != null && uploadfile.ContentLength > 0)
            {
                var fileName = Path.GetFileName(uploadfile.FileName);
                var path = Path.Combine(Server.MapPath("~/Uploads"), fileName);
                if (System.IO.File.Exists(path))
                    System.IO.File.Delete(path);
                uploadfile.SaveAs(path);
            }
            return Content("上傳完畢!");
        }

這樣就滿足了同時上傳文件的需要——在IE里。

--End--


免責聲明!

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



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