JavaScript文件上传和下载

前一段时间做附件的上传和下载功能。期间遇到不少问题,网上找的方法都不算完整。这里把前端和后端的实现都整理一下。

需要的东西:JQuery,Pako.jsbase64.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;
            }

    这样,一个简单的完整的文件下载功能就实现了

时间: 2024-10-29 09:21:57

JavaScript文件上传和下载的相关文章

文件上传与下载!

1.上传: 1.上传数据的类型:字符,字节 1.文本类型(字符):通过url网址的?:通过表单元素:AJAX. 2.文件类型(字节):通过表单元素(file). 2.上传文件的方式: 1.form表单实现文件上传:常用方式(上传文件用post,不用get,因为get方式对于上传量有限) 通过鼠标单击,在File标签中选择的文件,才能上传. 2.通过AJAX实现文件上传:禁用方式   AJAX的数据传递通过javascript脚本取值.如果传递文件,那么也需要通过javascript脚本获取文件内

springmvc和servlet下的文件上传和下载(存文件目录和存数据库Blob两种方式)

项目中涉及了文件的上传和下载,以前在struts2下做过,今天又用springmvc做了一遍,发现springmvc封装的特别好,基本不用几行代码就完成了,下面把代码贴出来: FileUpAndDown.jsp <%@ page language="java" contentType="text/html; charset=UTF-8"%> <html> <head> <title>using commons Uplo

aspx 文件上传和下载,多文件上传

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="MultiFileUpload.aspx.cs"  Inherits="MultiFileUpload"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org

JavaWeb学习总结(五十)——文件上传和下载

在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件.这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,stru

深入分析JavaWeb Item40 -- 文件上传和下载

在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件.这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,stru

struts2中的文件上传和下载

天下大事,必做于细.天下难事,必作于易. 曾经见过某些人,基础的知识还不扎实就去学习更难的事,这样必然在学习新的知识会很迷惑结果 再回来重新学习一下没有搞懂的知识,这必然会导致学习效率的下降!我写的这篇上传和下载都很基础. 十分适合初学者! jsp:页面 <!--在进行文件上传时,表单提交方式一定要是post的方式,因为文件上传时二进制文件可能会很大,还有就是enctype属性,这个属性一定要写成multipart/form-data, 不然就会以二进制文本上传到服务器端--> <for

JavaWeb文件上传和下载

在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请 求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件.这个common- fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,st

Linux 指令篇:文件上传和下载 lrzsz

[ "lrzsz"一般用于SecureCRT ssh中使用 ] 简介:rz,sz是早期Linux/Unix同Windows进行ZModem文件传输的命令行工具.rz ,sz 是非常古老的zmodem协议使用的上传下载命令,早就被抛弃了的东西,目前的发行版基本都不再预装. 优点:比ftp命令方便,而且服务器不用打开FTP服务. 命令sz:将选定的文件发送(send)到本地机器 命令rz:运行该命令会弹出一个文件选择窗口,从本地选择文件上传到Linux服务器. lrzsz安装方法: [[e

FileUpload系列:(3)文件上传和下载示例

示例由1个Servlet和3个JSP组成. 1.FileServlet package com.rk.web.servlet; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLEncoder; import java.util.Has