JavaScript文件上傳和下載

前一段時間作附件的上傳和下載功能。期間遇到很多問題,網上找的方法都不算完整。這裏把前端和後端的實現都整理一下。前端

須要的東西:JQuery,Pako.jsbase64.js。其中pako/base64是爲了對上傳的文件進行壓縮而使用。若是前端有對文件進行壓縮,那麼後端也應該對應進行解壓。node

上傳最簡單的實現:前端選擇一個文件-讀取文件信息-經過ajax請求後端方法把文件信息傳輸並保存(固然,當文件太大,在客戶端應該要分批讀取並上傳,在服務端也是依次分批保存)git

  • HTML只須要一個input
    <input type="file" id="filePicker" />
  • JS實現
    $(document).ready(function () {
        $(document).on("change", "#filePicker", onFileUpload);
    });
    
    function onFileUpload(e) {
        if (!window.FileReader) { // 使用了HTML 5 的 FileReader API。目前大部分瀏覽器都能支持。
            alert("該瀏覽器不支持HTML5,請升級或者更換其它瀏覽器。");
            return;
        }
        var fileInfo = e.currentTarget.files[0];
        var fileName = fileInfo.name;
        var fileSize = fileInfo.size;
    
        var fileReader = new FileReader();
        //var blob = fileInfo.slice(0, fileSize);
        //fileReader.readAsArrayBuffer(blob);
        fileReader.readAsArrayBuffer(fileInfo);
        fileReader.onload = function (result) {
            var pakoString = getUploadingFileContentString(this.result);
            $.ajax({
                url: "http://localhost/Server/ashx/FileProcess.ashx", //用通常處理程序接收請求
                type: "POST",
                data: {
                    fileContent: pakoString,
                    fileName: fileName
                },
                success: function (data) {
                    if (data == "True") {
                        alert("上傳成功!");
                    }
                    else {
                        alert("上傳失敗");
                    }
                },
                error: function (e) {
                    alert(e.responseText);
                }
            });
        }
    }
    
    function getUploadingFileContentString(readResult) {
        if (readResult == null) {
            return null;
        }
        var fileContentArr = new Uint8Array(readResult);
        var fileContentStr = "";
        for (var i = 0; i < fileContentArr.length; i++) {
            fileContentStr += String.fromCharCode(fileContentArr[i]);
        }
        //若是不壓縮,直接轉base64 string進行傳輸
        //window.btoa: 將ascii字符串或二進制數據轉換成一個base64編碼過的字符串,該方法不能直接做用於Unicode字符串.
        //var base64FileString = window.btoa(fileContentStr);
        //return base64FileString;
    
        //壓縮
        var pakoBytes = pako.gzip(fileContentStr);
        var pakoString = fromByteArray(pakoBytes);
        return pakoString;
    }
  • 服務端實現
    public class FileProcess : IHttpHandler
        {
    
            public void ProcessRequest(HttpContext context)
            {
                UploadFile(context);
            }
    
            private void UploadFile(HttpContext context)
            {
                var fileName = context.Request["fileName"];
                var compressedFileContent = context.Request["fileContent"];
                //若是前端沒有對文件進行壓縮,那麼直接獲取文件的字節數組便可
                //byte[] fileBytes = Convert.FromBase64String(compressedFileContent);
    
                //解壓
                var fileContent = GZip.GZipDecompress(compressedFileContent);
                byte[] fileBytes = Utils.ConvertJSBytes2Str(fileContent);
                bool isSavedSuccess = Utils.SaveFile2Disk(fileBytes, fileName, isUploadPartly);
    
                context.Response.Write(isSavedSuccess);
            }
    }
    
    //其中GZipDecompress
    /ConvertJSBytes2Str/SaveFile2Disk實現以下 public static string GZipDecompress(string zipString) { if (string.IsNullOrEmpty(zipString)) { return string.Empty; } byte[] zipBytes = Convert.FromBase64String(zipString); return System.Text.Encoding.UTF8.GetString(Decompress(zipBytes)); } private static byte[] Decompress(byte[] zipData) { MemoryStream m = new MemoryStream(zipData); GZipStream zipStream = new GZipStream(m, CompressionMode.Decompress); MemoryStream outStream = new MemoryStream(); byte[] buffer = new byte[1024]; while (true) { var readCount = zipStream.Read(buffer, 0, buffer.Length); if (readCount <= 0) { break; } outStream.Write(buffer, 0, readCount); } zipStream.Close(); return outStream.ToArray(); } public static byte[] ConvertJSBytes2Str(string fileContent) { if (string.IsNullOrEmpty(fileContent)) { return null; } // JS中,String.fromCharCode接受Unicode字符,並轉成字符串 byte[] fileBytes = System.Text.Encoding.Unicode.GetBytes(fileContent); byte[] adjustedFileBytes = new byte[fileBytes.Length / 2]; var index = 0; for (var i = 0; i < fileBytes.Length; i = i + 2) { adjustedFileBytes[index] = fileBytes[i]; index++; } return adjustedFileBytes; } public static bool SaveFile2Disk(byte[] fileContent, string fileName, bool isSavedPartly = false) { if (fileContent == null || fileContent.Length == 0) { throw new ArgumentNullException("文件內容不能爲空!"); } if (string.IsNullOrEmpty(fileName)) { throw new ArgumentNullException("文件名不能爲空!"); } var targetFloder = HttpContext.Current.Server.MapPath("~/UploadFileFloder/"); var fullPath = Path.Combine(targetFloder, fileName); DirectoryInfo di = new DirectoryInfo(targetFloder); if (di.Exists == false) { di.Create(); } FileStream fileStream; try { if (isSavedPartly) { fileStream = new FileStream(fullPath, FileMode.Append, FileAccess.Write, FileShare.Read, 1024); } else { fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.ReadWrite); } } catch (Exception ex) { //throw ex; //write log return false; } try { fileStream.Write(fileContent, 0, fileContent.Length); } catch (IOException ex) { //write log return false; } finally { fileStream.Flush(); fileStream.Close(); fileStream.Dispose(); } return true; }

    這樣,一個簡單的完整的前端到後端的文件上傳保存就完成了github

 下載文件。(這裏簡化程序,服務端指定的文件夾裏面已經有待下載的file1.txt)ajax

  • HTML
    <input type="button" id="downloadFileBtn" value="下載"/>
  • JS
    $(document).on("click", "#downloadFileBtn", downloadFile);
    
    function downloadFile()
    {
        var fileName = "file1.txt";
        $.ajax({
            url: "http://localhost/Server/ashx/FileProcess.ashx",
            type: "POST",
            success: function (data) {
                var fileContent = window.atob(data);
                saveFile(fileName, fileContent);
            },
            error: function (e) {
                alert(e.responseText);
            }
        });
    }
    function saveFile(fileName, fileContent) { var byteArr = new Array(fileContent.length); for (var i = 0; i < fileContent.length; i++) { byteArr[i] = fileContent.charCodeAt(i); } var blob = new Blob([new Uint8Array(byteArr)], { type: "application/octet-stream" }); var url = window.URL.createObjectURL(blob); var a = document.createElement("a"); if ("download" in a) { // 支持download屬性 document.body.appendChild(a); a.style = "display:none";
    a.href
    = url; //download屬性IE不支持。。。 a.download = fileName; a.click(); // 觸發下載 //revokeObjectURL會致使firefox不能下載。。。 //window.URL.revokeObjectURL(url); document.body.removeChild(a); } else { //IE 10+ if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { return navigator.msSaveOrOpenBlob(blob, name); } } }
  • 服務端實現
    //ProcessRequest中調用Download

    public void Download(HttpContext context)
     { var filePath = Path.Combine(HttpContext.Current.Server.MapPath("~/UploadFileFloder/"), "file1.txt"); byte[] fileContentBytes = Utils.GetByteArrayByFilePath(filePath); context.Response.Write(Convert.ToBase64String(fileContentBytes)); } //其中,GetByteArrayByFilePath實現以下
    public static byte[] GetByteArrayByFilePath(string fileFullPath) { if (string.IsNullOrEmpty(fileFullPath)) { return null; } FileStream fs = null; byte[] fileContent = null; try { FileInfo fi = new FileInfo(fileFullPath); fileContent = new byte[fi.Length]; //fs = new FileStream(fileFullPath, FileMode.Open);
                    fs = File.OpenRead(fileFullPath); fs.Read(fileContent, 0, fileContent.Length); } catch (Exception ex) { return null; } finally { if (fs != null) { fs.Close(); } } return fileContent; }

    這樣,一個簡單的完整的文件下載功能就實現了npm

相關文章
相關標籤/搜索