多日前的上篇介绍了csv表格,以及JS结合后端PHP解析表格填充表单的方法。其中csv转换成二维数组的时候逻辑比较复杂多坑,幸好PHP有丰富的库函数来处理,而现在用JS解析的话就没有那么幸运了,一切都要自己撸一个出来 或者 →_→ 引入一个库。

JS导入CSV--读取文本

JS能前端读取文件吗?以前只有通过 IE的ActiveXObject或者Flash才能本地读取文件。随着H5的出现,这个问题有普遍解了。Talk is cheap,show you the code

$.fn.csv2arr = function( ){
var files = $(this)[0].files;
if( typeof(FileReader) !== 'undefined' ){ //H5
var reader = new FileReader();
reader.readAsText( files[0] ); //以文本格式读取
reader.onload = function(evt){
var data = evt.target.result; //读到的数据
console.log(data);
}
}else{
alert("IE9及以下浏览器不支持,请使用Chrome或Firefox浏览器");
}
}
//调用方法
$("#startBtn").click(function(){
$("#csvInput").csv2arr();
});

这里的关键就是 FileReader,是H5标准里的读取文件的一个标准实现方式,IE10及以上版本以及chrome/firefox/safari等支持。调用方式方法也比较简单,只需要传入文件输入框的DOM,设定读取方式然后绑定回调函数就行了。这里使用的是 readAsText() 的方式,读取为文本格式。参考火狐的MDN文档,还有以base64,二进制等方式,可自行参考尝试。UTF8文本文件读取如下:

注意:readAsText()会自动把utf8文件的BOM头(如果有的话)去除,其它读取方式要注意手动去除。

题外话:为什么H5会出现这种直接读取本地文件的API,对安全的威胁大吗?其实这对浏览器用户的安全威胁是基本上没有扩大的,试想一下,原来没有这种读本地文件的API的时候,网站有没有获取本地文件的权限?当然是有的,还是通过这个input type="file",绑定一个onchange事件到 Ajax提交,用户的文件就悄悄地传到网站后端去了。这问题还是得靠提高网民的安全意识,像以前的钓鱼盗号网站,伪造个QQ登录界面就能坐收渔利。这种也能伪造一个下载按钮和对话框,诱导用户把重要机密文件上传上去。

JS导入CSV--文本解析插件

因为JS没有像PHP那样的CSV处理函数,上一篇文章说到里面有不少复杂情况要处理,那么最机(鸡)智(贼)的方法当然是:找插件。其中用的人最多的csv插件是PapaParse.js。经典的使用方法如下

// Parse local CSV file
$("#csvBtn").click(function(){ var file = $("input[name=csv]").[0].files[0];
Papa.parse(file, {
    complete: function(results) {
    console.log("Finished:", results.data);
    }
}); });

这个插件比较强大,解析上基本没有什么大问题,但仍然不是十分完善。问题如下:

  1. 文件最末尾的空行没有自动去除,可能会导致表单填多一点空数据;
  2. 不能自动识别UTF8与GBK,中文解析可能乱码;
  3. UTF8编码下, \r\n与\n混用时有可能会解析出问题,这个是PapaParse解析的算法问题,还请高手去其官方github提供修复。

JS导入CSV--编码自动识别

刚说到的第三点,如果表格内容有中文的话,就是个大问题了。因为一般网页的编码是UTF8,导出的表格也会是UTF8编码格式,如果不修改直接上传则为UTF8。但是如果修改,Windows平台下的常用表格软件包括Office和WPS全都将其转换成GBK编码。如果程序没有自动识别编码处理,将有很大概率导致乱码。

另一方面,如果网页使用GBK编码格式下载,也不能确保用户上传的文件就一定是GBK,因为MAC系统用的是UTF8,可能本来GBK的在修改后就成了UTF8了。

或者可以给个下拉栏让用户手动选择编码格式,但是你要指导用户知道编码格式是什么东西,怎么查看,这可不是什么容易让人接受的事。那怎么做编码自动识别呢?UTF8与GBK是不是有明显的编码特征用以区分,报歉的是还真没有。那怎么办?找轮子。在哪找?对于JS的轮子,国内有个很好的CDN库,虽然介绍是全英的但还是很好找。我们要找的是编码解码,那就Ctrl+F搜 encod (encode和encoding的前面几个单词),一个个看看介绍,还真能找到一个,名为jschardet。

点进去,没有详细说明,那就再去其github页。看看示例代码

// "àíàçã" in UTF-8
jschardet.detect("\xc3\xa0\xc3\xad\xc3\xa0\xc3\xa7\xc3\xa3")
// { encoding: "UTF-8", confidence: 0.9690625 } // "次常用國字標準字體表" in Big5
jschardet.detect("\xa6\xb8\xb1\x60\xa5\xce\xb0\xea\xa6\x72\xbc\xd0\xb7\xc7\xa6\x72\xc5\xe9\xaa\xed")
// { encoding: "Big5", confidence: 0.99 }

什么鬼?看起来用的好像不是普通字符串啊,看起来像是十六进制码的样子。实践了发现,传普通字符串进去全部都是识别为ASCII编码,确实有点难搞啊。怎么办呢?

莫慌莫慌,我们不是要读取本地文件拿来解析吗?再看看火狐的MDN文档除了readAsText()读取为字符串以外还有什么方法可以用。有个readAsBinaryString(),但是并不是标准的H5读取方法,有些浏览器可能不支持。再看有一个readAsDataURL(),这什么东西呢,试试便知道。结果得到一串这样的东西

data:text/csv;base64,NiywzczYwPvM2KGksLIKMyzN0LDdtvLLuaGkx+0KOCy2xc3+oaS3xrDCxMkK

改文件再试多几次,原来是这样子的:前面的 data:text/csv;base64, 是固定字符串,仅对火狐,chrome和IE前面的是 data:;base64, ,后面的那一串是文件内容经过base64编码而成。那么把后面这个一串解码出来看看,IE>=10、火狐、chrome有原生的base64解码函数 atob()。然后就得到了一个英文正常,中文全是乱码的字符串了,而且这个字符串的乱码看起来不像UTF8也不像GBK。那么很可能这就是十六进制码了吧,用jschardet检测一下,成功了!

总结整理

到这里,我们已经用第三方的JS解决了最大的两个难题,编码识别和CSV解析。那么就把这些整合一下,封装成一个更方便调用的方法吧

/**
* csv file to 2D arr
* */
$.fn.csv2arr = function( callback ){
if( typeof(FileReader) == 'undefined' ){ //if not H5
alert("IE9及以下浏览器不支持,请使用Chrome或Firefox浏览器\nYour browser is too old,please use Chrome or Firefox");
return false;
}
if( ! $(this)[0].files[0]){
alert("请选择文件\nPlease select a file");
return false;
}
var fReader = new FileReader();
fReader.readAsDataURL( $(this)[0].files[0] );
$fileDOM = $(this);
fReader.onload = function(evt){
var data = evt.target.result;
// console.log( data );
var encoding = checkEncoding( data );
// console.log(encoding);
//转换成二维数组,需要引入Papaparse.js
Papa.parse( $($fileDOM)[0].files[0], {
encoding: encoding,
complete: function(results) { // UTF8 \r\n与\n混用时有可能会出问题
// console.log(results);
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;
}
}

使用例子

<input type="file" name="csvfile" />
<input type="button" onclick="csv2()" value="JS转换"/> <script src="__PJS__/jquery.js"></script>
<script src="__PJS__/papaparse.js"></script>
<script src="__PJS__/jschardet.js"></script>
<script>
function csv2(){
$("input[name=csvfile]").csv2arr(function(res){
alertTips("F12打开浏览器控制台看看");
console.log( res );
});
}
</script>

下载与更新

演示地址DEMO

zip打包下载

Github地址,求加星,求一起修BUG

DRY--Don't Repeat Yourself. 别乱造些满是bug的轮子

csv表格处理(下)--纯JS解析导入csv的更多相关文章

  1. ios webview下纯JS实现长按

    app,其中有长按LI列表弹出菜单,只要清楚五个方法就行:ontouchstart.ontouchmove.ontouchend.setTimeout.clearTimeout 1.首先在我们按下手指 ...

  2. mysql SQLyog导入csv数据失败怎么办?

    分享下mysql使用SQLyog导入csv数据失败的解决方法 给mysql导入数据,选中某个表选择导入--导入使用本地csv数据即可,单有的时候不知道什么问题导入不成功!!! 给mysql导入数据,使 ...

  3. csv表格处理(上)-- JS 与 PHP 协作导入导出

    CSV简介 在开发后台管理系统的时候,几乎无可避免的会遇到需要导入导出Excel表格的需求.csv也是表格的一种,其中文名为“逗号分隔符文件”.在Excel中打开如下图左边所示,在记事本打开如下图右边 ...

  4. 【 D3.js 进阶系列 — 1.0 】 CSV 表格文件的读取

    在入门系列的教程中.我们经常使用 d3.json() 函数来读取 json 格式的文件.json 格式非常强大.但对于普通用户可能不太适合,普通用户更喜欢的是用 Microsoft Excel 或 O ...

  5. nodejs:导出Excel和解析导入的Excel

    用的是koa2框架,但好好处理一下,用express框架也是可以的.导出的Excel是xlsx的格式,解析导入Excel的有xlsx和csv格式.通常导入Excel是要上传的,然后获取文件的路径,这里 ...

  6. CSS控制XML与通过js解析xml然后通过html显示xml中的数据

    使用CSS控制XML的显示 book.css bookname{ display:block;color:Red} author{ display:block;font-style:italic} p ...

  7. 《项目经验》--后台一般处理程序向前台JS文件传递JSON,JS解析JSON,将数据显示在界面--显示在DropDownList 或 显示在动态创建的table中

    http://blog.csdn.net/mazhaojuan/article/details/8599167 先看一下我要实现的功能界面: 这篇文章主要介绍:后台一般处理程序把从数据库查找的数据,转 ...

  8. PHP处理CSV表格文件的常用操作方法是怎么样呢

    php来说,fgetcsv读入csv表格,返回一个数组,然后foreach输出成HTML的<table>,这步操作几行代码就能实现,非常简单.工作量主要还在于浏览器前端,建议你用jQuer ...

  9. 纯js实现分页

    原理:所有数据已加载好,js通过遍历部分显示,实现分页效果 html代码 <html> <head> <meta charset='utf-8'> <scri ...

随机推荐

  1. 使用swagger作为restful api的doc文档生成

    初衷 记得以前写接口,写完后会整理一份API接口文档,而文档的格式如果没有具体要求的话,最终展示的文档则完全决定于开发者的心情.也许多点,也许少点.甚至,接口总是需要适应新需求的,修改了,增加了,这份 ...

  2. Vmware虚拟机安装Ubuntu并设置root登陆

    主机操作系统是win7.在Ubuntu官网下好系统镜像.iso文件,安装好Vmware workstation软件 1 安装Ubuntu系统到Vmware虚拟机: 注意下面这步是无法直接设置账号为ro ...

  3. JavaScript结构三层——思想快速介绍

    本文版权归博客园和作者吴双本人所有,转载和爬虫请注明原文地址 http://www.cnblogs.com/tdws/,我是博客园蜗牛,我们共同进步. 今天讨论的是什么 如果你的工作中需要写JavaS ...

  4. iOS学习笔记——滚动视图(scrollView)

    滚动视图:在根视图中添加UIScrollViewDelegate协议,声明一些对象属性 @interface BoViewController : UIViewController<UIScro ...

  5. EC笔记:第三部分:14、在资源管理类中小心Copying行为

    场景 上一节实现了智能指针,其中的拷贝构造函数和赋值运算符是通过增加/减少指针的引用计数来操作的.但是如果是管理一个独占资源呢?我们希望在一个资源使用时被锁定,在使用完毕后被释放. #include ...

  6. tornado+sqlalchemy+celery,数据库连接消耗在哪里

    随着公司业务的发展,网站的日活数也逐渐增多,以前只需要考虑将所需要的功能实现就行了,当日活越来越大的时候,就需要考虑对服务器的资源使用消耗情况有一个清楚的认知.     最近老是发现数据库的连接数如果 ...

  7. 从DOM操作看Vue&React的前端组件化,顺带补齐React的demo

    前言 接上文:谈谈我对前端组件化中“组件”的理解,顺带写个Vue与React的demo 上次写完博客后,有朋友反应第一内容有点深,看着迷迷糊糊:第二是感觉没什么使用场景,太过业务化,还不如直接写Vue ...

  8. Using AlloyTouch to control three.js 3D model

    As you can see, the above cube rotation, acceleration, deceleration stop all through the AlloyTouch ...

  9. MAC的SVN怎么设置允许.a文件上传

    首先在mac中svn的安装会去选择Cornerstone 如果遇到这个问题肯定是已经安装并准备上传.a 文件了.首先要清楚svn是默认过滤忽略.a文件的上传的,要想可以上传.a 可以通过这个简单的方法 ...

  10. Android Studio多渠道打包

    本文所讲述的多渠道打包是基于友盟统计实施的. 多渠道打包的步骤: 1.在AndroidManifest.xml里设置动态渠道变量 <meta-data android:name="UM ...