关于vue导入csv文件格式错误,js-xlsx导入CSV文件中文乱码处理参考

时间:2024-03-17 10:14:50

最近在vue导入csv文件踩的一个坑,废话就不多说了,直接上源码和处理过程。

过程:我最近使用js-xlsx导入CSV文件时会出现中文乱码,其实这种问题基本上都是因为文件的编码不对造成的,因为使用这个插件用的比较多之前是可以直接使用UTF-8格式的csv文件导入的,但没想到还是出现了文件格式问题

这个是非UTF-8格式的,关于vue导入csv文件格式错误,js-xlsx导入CSV文件中文乱码处理参考

 这个是UTF-8格式的关于vue导入csv文件格式错误,js-xlsx导入CSV文件中文乱码处理参考

 关于vue导入csv文件格式错误,js-xlsx导入CSV文件中文乱码处理参考

然后,我们打开 https://oss.sheetjs.com/js-xlsx/ 测试下导入这个文件的结果 

源代码:

export function export_excel_to_json(evt) {//读取方法
	var wb; //读取完成的数据
	var rABS = false; //是否将文件读取为二进制字符串
	var isCSV;
	if(!evt.target.files) {
		return;
	}
	var f = evt.target.files[0];
	var reader = new FileReader();

	var pet = new Promise(function(resolve, reject) {
		reader.onload = function(e) {
			var data = e.target.result;
			var XLSX = require('xlsx');
			wb = null;
			if(isCSV) {
				data = new Uint8Array(data);
				let f = isUTF8(data);
				//console.log("是CSV文件,编码" + (f ? "是" : "不是") + "UTF-8");
				if(f) {
					data = e.target.result;
				} else {
					var str = cptable.utils.decode(936, data);
					wb = XLSX.read(str, {
						type: "string"
					});
				}
			} else {
				//console.log("不是CSV文件");
			}
			if(!wb) {
				wb = rABS || isCSV ? XLSX.read(btoa(fixdata(data)), {
					type: 'base64'
				}) : XLSX.read(data, {
					type: 'binary'
				});
			}
			//console.log(wb);
			//wb.SheetNames[0]是获取Sheets中第一个Sheet的名字
			//wb.Sheets[Sheet名]获取第一个Sheet的数据
			//console.log(JSON.stringify( XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]) ));
			var result = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
			resolve(result);
		}
		isCSV = f.name.split(".").reverse()[0] == "csv"; //判断是否是 CSV
		if(rABS || isCSV) {
			reader.readAsArrayBuffer(f);
		} else {
			reader.readAsBinaryString(f);
		}
		evt.value = "";

	}).catch(error => console.log(error));
	//console.log(pet);
	return pet;
}
function fixdata(data) { //文件流转BinaryString
	var o = "",
		l = 0,
		w = 10240;
	iconv.skipDecodeWarning = true;
	let str = iconv.encode(o, 'utf-8');
	for(; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)));
	o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)));
	return o;
}

我使用了https://github.com/wayfind/is-utf8/blob/master/is-utf8.js来处理这个问题 

 isUTF8.js

function isUTF8(bytes) { //非中文格式CSV文件转换UTF-8方法
	var i = 0;
	while(i < bytes.length) {
		if(( // ASCII
				bytes[i] == 0x09 ||
				bytes[i] == 0x0A ||
				bytes[i] == 0x0D ||
				(0x20 <= bytes[i] && bytes[i] <= 0x7E)
			)) {
			i += 1;
			continue;
		}

		if(( // non-overlong 2-byte
				(0xC2 <= bytes[i] && bytes[i] <= 0xDF) &&
				(0x80 <= bytes[i + 1] && bytes[i + 1] <= 0xBF)
			)) {
			i += 2;
			continue;
		}

		if(( // excluding overlongs
				bytes[i] == 0xE0 &&
				(0xA0 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
				(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF)
			) ||
			( // straight 3-byte
				((0xE1 <= bytes[i] && bytes[i] <= 0xEC) ||
					bytes[i] == 0xEE ||
					bytes[i] == 0xEF) &&
				(0x80 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
				(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF)
			) ||
			( // excluding surrogates
				bytes[i] == 0xED &&
				(0x80 <= bytes[i + 1] && bytes[i + 1] <= 0x9F) &&
				(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF)
			)
		) {
			i += 3;
			continue;
		}

		if(( // planes 1-3
				bytes[i] == 0xF0 &&
				(0x90 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
				(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF) &&
				(0x80 <= bytes[i + 3] && bytes[i + 3] <= 0xBF)
			) ||
			( // planes 4-15
				(0xF1 <= bytes[i] && bytes[i] <= 0xF3) &&
				(0x80 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
				(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF) &&
				(0x80 <= bytes[i + 3] && bytes[i + 3] <= 0xBF)
			) ||
			( // plane 16
				bytes[i] == 0xF4 &&
				(0x80 <= bytes[i + 1] && bytes[i + 1] <= 0x8F) &&
				(0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF) &&
				(0x80 <= bytes[i + 3] && bytes[i + 3] <= 0xBF)
			)
		) {
			i += 4;
			continue;
		}
		return false;
	}
	return true;
}

感谢这位老哥的解决方法https://www.jianshu.com/p/439fbc4a11a8