js導(dǎo)入csv文件娘侍,讀取文本
這里的關(guān)鍵就是 FileReader,是H5標準里的讀取文件的一個標準實現(xiàn)方式泳炉,IE10及以上版本以及chrome/firefox/safari等支持憾筏。調(diào)用方式方法也比較簡單,只需要傳入文件輸入框的DOM花鹅,設(shè)定讀取方式然后綁定回調(diào)函數(shù)就行了氧腰。這里使用的是 readAsText() 的方式,讀取為文本格式。
注意:readAsText()會自動把utf8文件的BOM頭(如果有的話)去除容贝,其它讀取方式要注意手動去除自脯。
var inputFile = document.querySelector("input[type='file']");
inputFile.onchange = (event) => {
var file = inputFile.files[0];
if( typeof(FileReader) !== 'undefined' ){ //H5
var reader = new FileReader();
reader.readAsText(file); //以文本格式讀取
reader.onload = function(evt){
var data = evt.target.result; //讀到的數(shù)據(jù)
console.log(data);
}
}else{
alert("IE9及以下瀏覽器不支持,請使用Chrome或Firefox瀏覽器");
}
}
最簡單的方式導(dǎo)入csv文件斤富,中文解析會亂碼
JS導(dǎo)入CSV--文本解析插件PapaParse.js
var inputFile = document.querySelector("input[type='file']");
inputFile.onchange = (event) => {
var file = inputFile.files[0];
Papa.parse(file, {
complete: function(results) {
console.log("Finished:", results.data);
}
});
}
這個插件比較強大膏潮,解析上基本沒有什么大問題,但仍然不是十分完善满力。問題如下:
- 文件最末尾的空行沒有自動去除焕参,可能會導(dǎo)致表單填多一點空數(shù)據(jù);
- 不能自動識別UTF8與GBK油额,中文解析可能亂碼叠纷;
- UTF8編碼下, \r\n與\n混用時有可能會解析出問題潦嘶,這個是PapaParse解析的算法問題涩嚣,還請高手去其官方github提供修復(fù)。
(如果我們能識別編碼掂僵,這就好解決了)
JS導(dǎo)入CSV--編碼自動識別jschardet.js
查看FileReader文檔航厚,除了readAsText()讀取為字符串以外,還有readAsBinaryString()(并不是標準的H5讀取方法锰蓬,有些瀏覽器可能不支持)幔睬、readAsDataURL()
使用readAsDataURL()打印結(jié)果:
data:text/csv;base64,NiywzczYwPvM2KGksLIKMyzN0LDdtvLLuaGkx+0KOCy2xc3+oaS3xrDCxMkK
改文件再試多幾次,原來是這樣子的:前面的 data:text/csv;base64, 是固定字符串芹扭,僅對火狐麻顶,chrome和IE前面的是 data:;base64, ,后面的那一串是文件內(nèi)容經(jīng)過base64編碼而成舱卡。那么把后面這個一串解碼出來看看辅肾,IE>=10、火狐灼狰、chrome有原生的base64解碼函數(shù) atob()宛瞄。然后就得到了一個英文正常,中文全是亂碼的字符串了交胚,而且這個字符串的亂碼看起來不像UTF8也不像GBK份汗。那么很可能這就是十六進制碼了吧,用jschardet檢測一下蝴簇,成功了杯活!
總結(jié)整理
到這里,我們已經(jīng)用第三方的JS解決了最大的兩個難題熬词,編碼識別和CSV解析旁钧。那么就把這些整合一下吸重,封裝成一個更方便調(diào)用的方法吧
var inputFile = document.querySelector("input[type='file']");
inputFile.onchange = (event) => {
// console.log(event);
var file = inputFile.files[0];
csv2arr(function(res){
console.log(res)
}, file);
}
function csv2arr(callback, file) {
var fReader = new FileReader();
fReader.readAsDataURL(file);
// 顯示進度
var progress = document.querySelector("progress");
progress.max = file.size;
progress.value = 0;
fReader.onprogress = (event) => {
progress.value = event.loaded;
}
fReader.onload = function (evt) {
var data = evt.target.result;
// console.log( data );
var encoding = checkEncoding(data);
// console.log(encoding);
//轉(zhuǎn)換成二維數(shù)組,需要引入Papaparse.js
Papa.parse(file, {
encoding: encoding,
complete: function (results) { // UTF8 \r\n與\n混用時有可能會出問題
var res = results.data;
if (res[res.length - 1] == "") { //去除最后的空行
res.pop();
}
callback && callback(res);
}
});
}
fReader.onerror = function (evt) {
// console.log(evt);
alert("文件已修改歪今,請重新選擇(Firefox)\nThe file has changed,please select again.(Firefox)");
}
//檢查編碼嚎幸,引用了 jschardet
function checkEncoding(base64Str) {
//這種方式得到的是一種二進制串
var str = atob(base64Str.split(";base64,")[1]);
// console.log(str);
//要用二進制格式
var encoding = jschardet.detect(str);
encoding = encoding.encoding;
console.log( encoding );
if (encoding == "windows-1252") { //有時會識別錯誤(如UTF8的中文二字)
encoding = "ANSI";
}
return encoding;
}
}