在es6之前,这件事只能丢给后端解决。
现在要尽善尽美地解决这件事情,还是得靠后端,因为后端可以读取BOM头。
Q: 什么是BOM头?
A: 类似WINDOWS自带的记事本等软件,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM)。它是一串隐藏的字符,用于让记事本等编辑器识别这个文件是否以UTF-8编码。对于 GBK,ANSI,UTF-8 格式的文件,第一个字符会是 0-9a-zA-Z-/. 之一
但是有一种情况可以由前端去判断,什么情况呢,就是我们只需要区分该TXT文件是UTF8还是UTF16的编码格式,并且该UTF8文件的第一个字符不是除了ASCII码表的其他字符,因为这些字符在UTF8编码的文件中为一个字节长度。
(字节、字符和编码的关系戳这里)
这种情况下,就可以采用本文所介绍的方法,当然了,最好还是前后端一齐检验逻辑比较严密。
先来看一些概念:
然后看一张字节表。
(图来自hongda: 字符,字节和编码)
由表可知,在UTF8的编码下,英文字符的字节数是1,而UTF16,英文字符的字节数则是大于1的数,也就是说,我们可以通过Uint8Array读取第一个字节,判断其是否是字符,来判断其是否是UTF8编码的文件。这也是这个方法的局限点,因为有些字符是两个字节编码的,我们无法通过判断第一个字节,将文件确定为UTF8编码格式。
将文件用二进制格式读取后,采用TypedArray的Uint8Array进行转换,而读出来是ASCII码,根据ASCII和字符的对应表进行判断即可。
/**
* @description: 二进制形式读取txt文件 并判断其是否为utf-8
* @param {type}
* @return:
*/
function readFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function (evt) {
resolve(evt.target.result);
};
reader.readAsArrayBuffer(file);
});
}
export const isUtf8 = async function (file) {
const res = await readFile(file);
const firstCode = new Uint8Array(res)[0];
return firstCode >= 33 && firstCode <= 126;
};