前端js实现下载文件、读取上传文件的内容

写在前面

在实际开发过程中经常会碰到用户要下载或者导出一个文件的需求。传统的做法是在后端存储或者即时生成一个文件来提供下载功能,这样的优势是可以做权限控制、方便数据二次处理,但缺点是需要额外发起请求、增大服务端压力、下载速度慢。但随着HTML5的标准发布,我大前端已经完全可以独立实现文件下载与导出啦~

利用a标签的 download 属性下载文件

download属性指示浏览器下载 URL而不是导航到它,因此将提示用户将其保存为本地文件。如果属性有一个值,那么此值将在下载保存过程中作为预填充的文件名(如果用户需要,仍然可以更改文件名)。此属性对允许的值没有限制,但是 / 和 \ 会被转换为下划线。大多数文件系统限制了文件名中的标点符号,故此,浏览器将相应地调整建议的文件名。

<a download="文件名" href="文件地址">下载测试</a>

需要注意的是:

  1. download 仅适用于同源 URL,但是可以使用 blob: URL 和 data: URL。
  2. 如果 HTTP 头中的 Content-Disposition 属性赋予了一个不同于此属性的文件名,HTTP 头属性优先于此属性。
  3. 如果 HTTP 头属性 Content-Disposition 被设置为inline 即Content-Disposition='inline',那么 Firefox 优先考虑 HTTP 头 Content-Disposition download 属性。

生成Data URLs 并下载文件

Data URL 即前缀为 data: 协议的URL,其允许内容创建者向文档中嵌入小文件。它 由四个部分组成:前缀(data:)、指示数据类型的MIME类型、如果非文本则为可选的base64标记、数据本身。

data:[<mediatype>][;base64],<data>

mediatype 是个 MIME 类型的字符串
例如 "image/jpeg" 表示 JPEG 图像文件。
如果被省略,则默认值为 text/plain;charset=US-ASCII
如果数据是文本类型,你可以直接将文本嵌入 
如果是二进制数据,你可以将数据进行base64编码之后再进行嵌入。

导出文件代码示例:

//导出Json文件
exportJson(){
    const downloadData = {
        name:"April",
        ager:"18",
        hobby:"学习"
    };
    let dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(downloadData));
    let downloadAnchorNode = document.createElement('a')
    downloadAnchorNode.setAttribute("href", dataStr);
    downloadAnchorNode.setAttribute("download", "文件名.json")
    downloadAnchorNode.click();
    downloadAnchorNode.remove();
},

生成blob: URL 并下载文件

Blob()构造函数返回一个新的 Blob 对象。 blob的内容由参数数组中给出的值的串联组成。

let aBlob = new Blob( array, options );

array 是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings会被编码为UTF-8。

options 是一个可选的BlobPropertyBag字典,它可能会指定如下两个属性:

  1. type,默认值为 "",它代表了将会被放入到blob中的数组内容的MIME类型。
  2. endings,默认值为"transparent",用于指定包含行结束符\n的字符串如何被写入。 它是以下两个值中的一个: "native",代表行结束符会被更改为适合宿主操作系统文件系统的换行符,或者 "transparent",代表会保持blob中保存的结束符不变 。

URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。

objectURL = URL.createObjectURL(object);

导出文件代码示例:

exportJson() {
    const downloadData = {
        name: "April",
        ager: "18",
        hobby: "学习"
    };
                
    let blob = new Blob(
        [JSON.stringify(downloadData, null, 2)],
        {type: 'application/json'});
    let url = URL.createObjectURL(blob);
    let downloadAnchorNode = document.createElement('a')
    downloadAnchorNode.setAttribute("href", url);
    downloadAnchorNode.setAttribute("download", "文件名.json")
    downloadAnchorNode.click();
    downloadAnchorNode.remove();
 }

读取上传文件的数据

想要读取Blob数据的唯一方法是FileReader。
FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 FileBlob 对象指定要读取的文件或数据。

其中File对象可以是来自用户在一个<input>元素上选择文件后返回的FileList对象,也可以来自拖放操作生成的 DataTransfer对象,还可以是来自在一个HTMLCanvasElement上执行mozGetAsFile()方法后返回结果。

包含5个方法:

  1. FileReader.abort()
    中止读取操作。在返回时,readyState属性为DONE。

  2. FileReader.readAsArrayBuffer()
    开始读取指定的 Blob中的内容, 一旦完成, result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象.

  3. FileReader.readAsBinaryString()
    开始读取指定的Blob中的内容。一旦完成,result属性中将包含所读取文件的原始二进制数据。

  4. FileReader.readAsDataURL()
    开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容。

  5. FileReader.readAsText()
    开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个字符串以表示所读取的文件内容。

将上传的文件读取为字符串的代码示例

handleUpload(blob) {
    // 新建一个FileReader
    const reader = new FileReader()
    // 读取文件
    reader.readAsText(blob, "UTF-8")
    // 读取完文件之后会回来这里
    reader.onload = function (e) {
        // 读取文件内容
        const fileString = e.target.result
        // 接下来可对文件内容进行处理
        const myData = JSON.parse(fileString);
        console.log(myData) // 打印读取到的内容
     }
},

将上传的文件读取为URL格式的字符串的代码示例

handleUpload(file) {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function (e) {
        const urlStr = reader.result
        console.log(urlStr)
    }

点击下载图片

虽然目前浏览器都支持保存图片到本地的功能(右键>图片另存为)但是实际开发中会涉及到批量下载图片、Canvas绘图的保存功能,应运上面的知识,我大前端也可以轻松实现。代码如下:

 <button @click="downloadImg">下载图片</button>
// 通过src获取图片的blob对象
getImageBlob(url, cb) {
    let xhr = new XMLHttpRequest();
    xhr.open("get", url, true);
    xhr.responseType = "blob";
    xhr.onload = function () {
        if (this.status == 200) {
            cb(this.response);
        }
    };
    xhr.send();
},
// 点击下载图片
downloadImg(){
    let reader = new FileReader();
    this.getImageBlob('https://b-gold-cdn.xitu.io/v3/static/img/simplify-logo.3e3c253.svg', function(blob){
        // 读取来看下下载的内容 最终生成的字符串
        reader.readAsDataURL(blob);
        // 生成下载用的URL对象
        let url = URL.createObjectURL(blob);
        // 生成一个a标签,并模拟点击,即可下载,批量下载同理
        let downloadAnchorNode = document.createElement('a')
        downloadAnchorNode.setAttribute("href", url);
        downloadAnchorNode.setAttribute("download", "下载图片")
        downloadAnchorNode.click();
        downloadAnchorNode.remove();
    })
},
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容