天天看點

JavaScript檔案上傳和下載下傳

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

需要的東西:JQuery,Pako.js,base64.js。其中pako/base64是為了對上傳的檔案進行壓縮而使用。如果前端有對檔案進行壓縮,那麼後端也應該對應進行解壓。

上傳最簡單的實作:前端選擇一個檔案-讀取檔案資訊-通過ajax請求後端方法把檔案資訊傳輸并儲存(當然,當檔案太大,在用戶端應該要分批讀取并上傳,在服務端也是依次分批儲存)

  • 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;
            }      
    這樣,一個簡單的完整的前端到後端的檔案上傳儲存就完成了

 下載下傳檔案。(這裡簡化程式,服務端指定的檔案夾裡面已經有待下載下傳的file1.txt)

  • 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;
            }      
    這樣,一個簡單的完整的檔案下載下傳功能就實作了

轉載于:https://www.cnblogs.com/herohh/p/7586963.html

繼續閱讀