前端下载文件与读取文件内容(多种类型的文件)

写在前面

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

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

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

<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标记、数据自己。java

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

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

导出文件代码示例:git

//导出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的内容由参数数组中给出的值的串联组成。github

let aBlob = new Blob( array, options );
复制代码

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

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

  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();
 }
复制代码

点击下载图片

虽然目前浏览器都支持保存图片到本地的功能(右键>图片另存为)可是实际开发中会涉及到批量下载图片、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();
    })
},
复制代码

下载表格

推荐由SheetJS出品的js-xlsx是一款很是方便的只须要纯JS便可读取和导出excel的工具库,功能强大,支持格式众多,支持xls、xlsx、ods(一种OpenOffice专有表格文件格式)等十几种格式。本文所有都是以xlsx格式为例。 官方github:github.com/SheetJS/js-…

// 测试用的数据
staff: [
    {name: "April", job: "programmer", age: "18", hobby: "study"},
    {name: "Shawn", job: "student", age: "8", hobby: "study"},
    {name: "Leo", job: "teacher", age: "28", hobby: "play"},
    {name: "Todd", job: "programmer", age: "19", hobby: "sleep"},
    {name: "Scoot", job: "cook", age: "38", hobby: "paintting"},
]
复制代码

安装xlsx

npm install xlsx --save
复制代码
import XLSX from 'xlsx';
复制代码
auto_width(ws, data) {
    /*set worksheet max width per col*/
    const colWidth = data.map(row => row.map(val => {
        /*if null/undefined*/
        if (val == null) {
            return {'wch': 10};
        }
        /*if chinese*/
        else if (val.toString().charCodeAt(0) > 255) {
            return {'wch': val.toString().length * 2};
        } else {
            return {'wch': val.toString().length};
        }
    }))
    /*start in the first row*/
    let result = colWidth[0];
    for (let i = 1; i < colWidth.length; i++) {
        for (let j = 0; j < colWidth[i].length; j++) {
            if (result[j]['wch'] < colWidth[i][j]['wch']) {
                result[j]['wch'] = colWidth[i][j]['wch'];
            }
        }
    }
    ws['!cols'] = result;
},
json_to_array(key, jsonData) {
    return jsonData.map(v => key.map(j => {
        return v[j]
    }));
},
export_array_to_excel({key, data, title, filename, autoWidth}) {
    const wb = XLSX.utils.book_new();
    const arr = this.json_to_array(key, data);
    arr.unshift(title);
    const ws = XLSX.utils.aoa_to_sheet(arr);
    if (autoWidth) {
        this.auto_width(ws, arr);
    }
    XLSX.utils.book_append_sheet(wb, ws, filename);
    XLSX.writeFile(wb, filename + '.xlsx');
},
exportExcel() {
    let staff = this.staff;
    const params = {
        title: ['姓名', '工做', '年龄', '爱好'],
        key: ['name', 'job', 'age', 'hobby'],
        data: staff,
        autoWidth: true,
        filename: '文件名'
    }
    this.export_array_to_excel(params)
},
复制代码

读取上传文件的数据

想要读取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)
    }
}
复制代码

读取上传Excel文件

一样推荐由SheetJS出品的js-xlsx

import XLSX from 'xlsx';
复制代码
handleUpload(file) {
    let that = this;
    var reader = new FileReader();
    reader.readAsBinaryString(file);
    reader.onload = function (evt) {
      var data = evt.target.result;
      var workbook = XLSX.read(data, {
        type: 'binary'
      }) // 以二进制流方式读取获得整份excel表格对象
    }
    reader.onload = function (evt) {
      //当读取完成后回调这个函数,而后此时文件的内容存储到了result中,直接操做便可
      try {
        var data = evt.target.result,
          workbook = XLSX.read(data, {
            type: 'binary'
          }), // 以二进制流方式读取获得整份excel表格对象
          buildings = []; // 存储获取到的数据
        var fromTo = '';
        // 遍历每张表读取
        for (var sheet in workbook.Sheets) {
          if (workbook.Sheets.hasOwnProperty(sheet)) {
            fromTo = workbook.Sheets[sheet]['!ref'];
            buildings = buildings.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet]));
          }
        }
        console.log(buildings) // 文件内容
      } catch (e) {
        console.log('文件类型不正确', e);
        return;
      }
    }
    return false;
},
复制代码
相关文章
相关标签/搜索