loading

文件流的转换与下载

# 使用createObjectURL遇到的问题

# 在chrome中的表现

blob:http://172.28.74.136:8019/c2c5811e-906b-48d1-93a8-edb89c237f54

# 在IE中的表现

blob:9C9B0F3D-3E46-46F3-95AF-524089FB5E0F

# 第一时间想到的时候,createObjectURL这个属性的兼容问题,在ie中生成的链接不一样,于是决定手动去拼接一个和chrome一样的地址

# blob:${window.location.origin}/${URL.createObjectURL(blob).split(':')[1]}

结果遇到了另外一个坑,window.location.origin在IE中的结果是Undefined。。。换种方式拼接

# blob:${window.location.protocol}//${window.location.host}/${URL.createObjectURL(blob).split(':')[1]}

难受的是拼好也没用,在IE中,这样的方式也无法下载文件,于是乎,谷歌搜索。

# 解决方式

window.navigator.msSaveOrOpenBlob(blob, filename)

# 文件流

# 文件流相关接口

# 文件流转换

# 1、file转base64

/**
 * 上传附件转base64
 * @param {File} file 文件流
 */
export const fileByBase64 = (file, callback) => {
  var reader = new FileReader();
  // 传入一个参数对象即可得到基于该参数对象的文本内容
  reader.readAsDataURL(file);
  reader.onload = function (e) {
    // target.result 该属性表示目标对象的DataURL
    console.log(e.target.result);
    callback(e.target.result)
  };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 2、base64转blob

/**
 * base64转Blob
 * @param {*} data 
 */
export const base64ByBlob = (base64, callback) => {
  var arr = base64.split(','), mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  console.log(new Blob([u8arr], { type: mime }))
  callback(new Blob([u8arr], { type: mime }))
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 3、blob转url

var url = window.URL.createObjectURL(blob)
1

# 4、使用demo

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>文件流的转换与下载</title>
  </head>
  <body>
    <input type="file" id="input"/>
  </body>
  <script>
    const input = document.querySelector("input");
    input.addEventListener("input", inputChanged);
    function inputChanged(e) {
      console.log(e.target.files[0], "files");
      fileByBase64(e.target.files[0], () => {});
      //   fileByBase64(e.target.files[0], base64ByBlob);
    }
    const fileByBase64 = (file, callback) => {
      var reader = new FileReader();
      // 传入一个参数对象即可得到基于该参数对象的文本内容
      reader.readAsDataURL(file);
      reader.onload = function (e) {
        // target.result 该属性表示目标对象的DataURL
        console.log(e.target.result, "fileByBase64");
        callback(e.target.result);
      };
    };
    const base64ByBlob = (base64) => {
      var arr = base64.split(","),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      const blob = new Blob([u8arr], { type: mime });
      console.log(blob, "base64ByBlob");
      // console.log(window.URL.createObjectURL(blob), "URL");
      //   downloadByFile(blob);
      //   callback(new Blob([u8arr], { type: mime }));
    };
    const downloadByFile = (blob) => {
      // 创建a标签
      const alink = document.createElement("a");
      // 文件名
      alink.download = "backup.txt";
      // 开始下载
      alink.style.display = "none";
      // for IE
      if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveOrOpenBlob(blob, "backup.txt");
      } else {
        // for No-IE
        alink.href = URL.createObjectURL(blob);
        document.body.appendChild(alink);
        // 触发点击a标签事件
        alink.click();
        document.body.removeChild(alink);
      }
    };
  </script>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

# 文件下载

import axios from 'axios';
import request from '@/utils/request';
axios.defaults.timeout = 1000 * 60 * 5;

// 取response中的文件名称
const getFileNameFromHeader = headers => {
  if (!headers) {
    return '';
  }
  const contentDisposition = headers['content-disposition'];
  if (!contentDisposition) {
    return '';
  }
  const reg = /filename=(.*)/;
  const result = reg.exec(contentDisposition);
  return result ? decodeURI(result[1]) : '';
};

export default {
  // 下载文件, 传入文件流
  downloadByFile (res) {
    // 处理返回的文件流
    const content = res.data;
    const headers = res.headers;
    // 创建a标签
    const alink = document.createElement('a');
    // 文件名
    alink.download = getFileNameFromHeader(headers);
    // 开始下载
    alink.style.display = 'none';
    const blob = new Blob([content]);
    // for IE
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
      window.navigator.msSaveOrOpenBlob(blob, getFileNameFromHeader(headers));
    } else {
      // for No-IE
      alink.href = URL.createObjectURL(blob);
      document.body.appendChild(alink);
      // 触发点击a标签事件
      alink.click();
      document.body.removeChild(alink);
    }
  },

  // 下载文件, 传入接口名
  downloadByUrl (exportParams) {
    return new Promise(async (resolve, reject) => {
      const {
        url,
        params,
        fileName,
        method
      } = exportParams;
      const requestParams = {
        url: url,
        method: method || 'get',
        responseType: 'blob'
      };
      // 接口请求方式
      if (method === 'post') {
        requestParams.data = params;
      } else {
        requestParams.params = params;
      }
      try {
        const res = await request(requestParams);
        // 请求成功
        resolve(res);
        // 处理返回的文件流
        const content = res.data;
        const headers = res.headers;
        // 创建a标签
        const alink = document.createElement('a');
        // 文件名
        if (fileName) {
          alink.download = fileName;
        } else {
          alink.download = getFileNameFromHeader(headers);
        }
        // 开始下载
        alink.style.display = 'none';
        const blob = new Blob([content]);
        // for IE
        if (window.navigator && window.navigator.msSaveOrOpenBlob) {
          window.navigator.msSaveOrOpenBlob(blob, getFileNameFromHeader(headers));
        } else {
          // for No-IE
          alink.href = URL.createObjectURL(blob);
          document.body.appendChild(alink);
          // 触发点击a标签事件
          alink.click();
          document.body.removeChild(alink);
        }
      } catch (err) {
        reject(err);
      }
    });
  }
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

# 大文件上传 与 断点续传

  • 大文件上传基本都是分片,Blob.slice
  • 断点续传:根据文件内容生成hash作为分片的名称,然后和服务端比对,上传过的不再上传。

参考这篇文章,讲的很清楚 :字节跳动面试官:请你实现一个大文件上传和断点续传 (opens new window)

# 参考

最近更新时间: 2021/06/17 10:13:36
最近更新
01
2023/07/03 00:00:00
02
2023/04/22 00:00:00
03
2023/02/16 00:00:00