前端导出GBK编码的流文件及GBK转码UTF-8

1,917 阅读4分钟

导入文件

前端导出流文件方法

const downJMFile = (res) => {
  const data = res.data;
  if (typeof window.navigator.msSaveBlob !== 'undefined') {
    window.navigator.msSaveBlob(new Blob([data]), fileName);
  } else {
    const url = window.URL.createObjectURL(new Blob([data]));
    const link = document.createElement('a');
    link.style.display = 'none';
    link.href = url;
    link.setAttribute('download', fileName);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link); // 下载完成移除元素
    window.URL.revokeObjectURL(url); // 释放掉blob对象
  }
 }

axios请求

一开始axios的请求方式为 axios.post(url, data)

接口返回格式为

image.png 可以看出data不是流的形式

所以axios发送请求方式也要调整,改为axios.post(url, data, {responseType: 'blob'})

这样就可以了

1654400879738.png

!!!!但是有时候还是不行

这是因为项目中引入了mockjs

mock模块会影响原生的ajax请求,使得服务器返回的blob类型变成乱码

image.png 源码这这里直接把responseType设置为空字符串了, 所以项目中不引入mockjs就可以了

文件名称为GBK转码为UTF-8

首先安装iconv-lite插件

cnpm i iconv-lite

一般文件名都在响应头中,所以代码如下

 import iconvLite from 'iconv-lite';

  // filenameGBK格式的文件名
  const filenameGBK = res.headers['content-disposition'].match(/filename=(.*)(;)*/)[1] || '文件名';
  const fileName = iconvLite.decode(filenameGBK, 'gbk');

额外知识

GBK和UTF8有什么区别

GBK编码: 是指中国的中文字符,其它它包含了简体中文与繁体中文字符,另外还有一种字符'gb2312"这种字符仅能存储简体中文字符。

UTF-8编码: 它是一种全国家通过的一种编码,如果你的网站涉及到多个国家的语言,那么建议你选择UTF-8编码。

特点:

UTF8编码格式很强大,支持所有国家的语言,正是因为它的强大,才会导致它占用的空间大小要比GBK大,对于网站打开速度而言,也是有一定影响的。

GBK编码格式,它的功能少,仅限于中文字符,当然它所占用的空间大小会随着它的功能而减少,打开网页的速度比较快。

Blob对象

var blob = new Blob(dataArr:Array, opt:{type:string});

dataArray:数组,包含了要添加到Blob对象中的数据,数据可以是任意多个ArrayBuffer,ArrayBufferView, Blob,或者 DOMString对象。

opt:对象,用于设置Blob对象的属性(如:MIME类型)

关于MIME类型,其实不需要记,用的时候查阅一下就可以了,我之前在文件上传的时候列举过一些,需要的可以点击查看

除了这些,我再补充几个

.dot    application/msword
.docx    application/vnd.openxmlformats-officedocument.wordprocessingml.document
.dotx    application/vnd.openxmlformats-officedocument.wordprocessingml.template
.docm    application/vnd.ms-word.document.macroEnabled.12
.dotm    application/vnd.ms-word.template.macroEnabled.12
.xls    application/vnd.ms-excel
.xlt    application/vnd.ms-excel
.xla    application/vnd.ms-excel
.xlsx    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.xltx    application/vnd.openxmlformats-officedocument.spreadsheetml.template
.xlsm    application/vnd.ms-excel.sheet.macroEnabled.12
.xltm    application/vnd.ms-excel.template.macroEnabled.12
.xlam    application/vnd.ms-excel.addin.macroEnabled.12
.xlsb    application/vnd.ms-excel.sheet.binary.macroEnabled.12
.ppt    application/vnd.ms-powerpoint
.pot    application/vnd.ms-powerpoint
.pps    application/vnd.ms-powerpoint
.ppa    application/vnd.ms-powerpoint
.pptx    application/vnd.openxmlformats-officedocument.presentationml.presentation
.potx    application/vnd.openxmlformats-officedocument.presentationml.template
.ppsx    application/vnd.openxmlformats-officedocument.presentationml.slideshow
这些主要是office相关的,其他的请看我之前的文章。

1、创建一个装填DOMString对象的Blob对象

let haorooms ="<div>hello haorooms</div>";
let blob = new Blob([haorooms],{type:'text/xml'})
blob
 
//Blob(25) {size: 25, type: "text/xml"}

2、创建一个装填ArrayBuffer对象的Blob对象

let haorooms =new ArrayBuffer(8);
let blob = new Blob([haorooms],{type:'text/plain'})
blob
// 输出:Blob(8) {size: 8, type: "text/plain"}

3、Blob.slice()

Blob.slice(start:number, end:number, contentType:string)
 
start:开始索引,默认为0
end:截取结束索引(不包括end)
contentType:新Blob的MIME类型,默认为空字符串
例子:

let blob = new Blob(['haorooms ceshi duixiadasdadadad'],{type:'text/plain'})
let b2 = blob.slice(0,5,'text/plain')
b2
Blob(5) {size: 5, type: "text/plain"}

4、canvas.toBlob()

var canvas = document.getElementById("canvas");
canvas.toBlob(function(blob){
    console.log(blob);
});
预览canvas

blob应用

1、通过url显示图片

我们上传文件预览,一般都是预览blob对象路径。 img的src属性及background的url属性,都可以通过接收图片的网络地址或base64来显示图片,同样的,我们也可以把图片转化为Blob对象,生成URL(URL.createObjectURL(blob)),来显示图片。

2、文件下载

假如后端返回的是二进制的流文件编码,我们可以通过blob来下载

this.$http.get('请求地址', { params: params, responseType: 'arraybuffer' }).then(response => {
  var data = new Blob([response.body], { type: 'application/ms-excel' })// type也可以用application/vnd.ms-excel 按照上面的
  var downloadUrl = window.URL.createObjectURL(data)
  var anchor = document.createElement('a')
  anchor.href = downloadUrl
  anchor.download = `文件名${new Date().getTime()}.xls`
  anchor.click()
  window.URL.revokeObjectURL(data)
})

3、文件分片上传

通过Blob.slice方法,可以将大文件分片,轮循向后台提交各文件片段,即可实现文件的分片上传。

思路如下:

获取要上传文件的File对象,根据chunk(每片大小)对文件进行分片

通过post方法轮循上传每片文件,其中url中拼接querystring用于描述当前上传的文件信息;post body中存放本次要上传的二进制数据片段

接口每次返回offset,用于执行下次上传

下面是分片上传的简单实现:

initUpload();
 
//初始化上传
function initUpload() {
    var chunk = 100 * 1024;   //每片大小
    var input = document.getElementById("file");    //input file
    input.onchange = function (e) {
        var file = this.files[0];
        var query = {};
        var chunks = [];
        if (!!file) {
            var start = 0;
            //文件分片
            for (var i = 0; i < Math.ceil(file.size / chunk); i++) {
                var end = start + chunk;
                chunks[i] = file.slice(start , end);
                start = end;
            }
 
            // 采用post方法上传文件
            // url query上拼接以下参数,用于记录上传偏移
            // post body中存放本次要上传的二进制数据
            query = {
                fileSize: file.size,
                dataSize: chunk,
                nextOffset: 0
            }
 
            upload(chunks, query, successPerUpload);
        }
    }
}
 
// 执行上传
function upload(chunks, query, cb) {
    var queryStr = Object.getOwnPropertyNames(query).map(key => {
        return key + "=" + query[key];
    }).join("&");
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "http://xxxx/opload?" + queryStr);
    xhr.overrideMimeType("application/octet-stream");
 
    //获取post body中二进制数据
    var index = Math.floor(query.nextOffset / query.dataSize);
    getFileBinary(chunks[index], function (binary) {
        if (xhr.sendAsBinary) {
            xhr.sendAsBinary(binary);
        } else {
            xhr.send(binary);
        }
 
    });
 
    xhr.onreadystatechange = function (e) {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                var resp = JSON.parse(xhr.responseText);
                // 接口返回nextoffset
                // resp = {
                //     isFinish:false,
                //     offset:100*1024
                // }
                if (typeof cb === "function") {
                    cb.call(this, resp, chunks, query)
                }
            }
        }
    }
}
 
// 每片上传成功后执行
function successPerUpload(resp, chunks, query) {
    if (resp.isFinish === true) {
        alert("上传成功");
    } else {
        //未上传完毕
        query.offset = resp.offset;
        upload(chunks, query, successPerUpload);
    }
}
 
// 获取文件二进制数据
function getFileBinary(file, cb) {
    var reader = new FileReader();
    reader.readAsArrayBuffer(file);
    reader.onload = function (e) {
        if (typeof cb === "function") {
            cb.call(this, this.result);
        }
    }
}

原文链接:blog.csdn.net/weixin_4172…