前端解析CSV实践总结

由于网络的资源比较杂乱,自己看了并实践之后,总结一下

方法1: Input + FileReader 原生 API 的方式

首先通过inputtype='file'输入框获取文件,然后通过浏览器提供的原生 File API 中的 FileReader 来读取本地文件。

代码如下

html 复制代码
  <input id="myFileInput" type="file" />

由于文件读取是异步的,我们需要在读取完成后获取到文件内容。因此,我们需要监听FileReader 对象的 load 事件,这个事件在文件读取完成后触发。

js 复制代码
const read = () => {
  var fileInput = document.getElementById("myFileInput");

  var file = fileInput.files[0];
  
  var reader = new FileReader();
  
  reader.readAsText(file);

  reader.addEventListener("load", function () {
    var csvContent = reader.result;
    console.log(csvContent, 'csvContent');

    var records = csvContent.split("\n");

    var result = [];
    
    for (var i = 1; i < records.length; i++) {
        var fields = records[i].split(",");
        var record = {
            time: fields[0],
            station_name: fields[1],
            meter_kwh: fields[2]
        };
        result.push(record);
    }
    console.log(result, 'result');
  });
}

这种方式需要手动解析数据。因为 csvContent 是一个 string 类型。如下

js 复制代码
time,station_name,meter_kwh
2021/10/1 0:00,一号电站,54.91870189
2021/10/1 0:00,二号电站,73.62640804
2021/10/1 0:00,三号电站,11.42062977

我们一般拿到这种数据,不管是填充到表格里面还是 Echarts,Antv 里都是需要转换一下的。因此在这里手动转换。转换的时候需要知道 key 的值,这里是写死的。所以有一定缺点。 这种方式是用户通过 Input 框来上传一个文件,然后前端进行解析。

方法2:Input + Papaparse 解析 csv

Papaparse 是一个比较好用的解析 csv 的工具。并且提供了 Demo,非常方便。 从 Demo 可以看到,包含解析 csv 字符串,解析通过 Input 输入框上传的文件,解析远程 URL资源形式的 csv 文件,将 json 解析成 csv。

注:papaparse 解析本地文件, 需要的文件格式是从 DOM 中获得的 File 对象, 不能直接使用 require() 导入文件。所以需要借助 Input。

通过 Papaparse 就可以将方法1中的代码进行优化,直接使用框架而不是手动解析。代码如下:

js 复制代码
import Papa from 'papaparse';

const read2 = () => {
  var fileInput = document.getElementById("myFileInput");
  var file = fileInput.files[0];
  Papa.parse(file,  {
    // header: true,
    delimiter: ',', // 字段分隔符
    complete: (results) => {
      console.log(results, 'results')
      const csvData = results.data
    }
  });
  ;
}

这里的 Result 结构是下面这样的:

js 复制代码
results = {
	data: [
      ['time', 'station_name', 'meter_kwh'],
      ['2021/10/1 0:00', '一号电站', '54.91870189'],
      ['2021/10/1 0:00', '二号电站', '73.62640804'],
      ['2021/10/1 0:00', '三号电站', '11.42062977']
    ], // parsed data
	errors: [],  // errors encountered
	meta: {
      delimiter: ',',
      linebreak: '\r\n',
      aborted: false,
      truncated: false,
      cursor: 2372
    } // extra parse info
}

如果想要转换成我们想要的通用的数据结构的话,Papaparse 提供了一个很方便的属性,就是 header: true。在 Papa.parse 的第二个参数里面加上即可。转换之后如下,从 data 拿数据即可。

js 复制代码
results = {
	data: [
    {time: '2021/10/1 0:00', station_name: '一号电站', meter_kwh: '54.91870189'},
    {time: '2021/10/1 0:00', station_name: '二号电站', meter_kwh: '73.62640804'},
    {time: '2021/10/1 0:00', station_name: '三号电站', meter_kwh: '11.42062977'}
    ], // parsed data
	errors: [],  // errors encountered
	meta: {
      delimiter: ',',
      linebreak: '\r\n',
      aborted: false,
      truncated: false,
      cursor: 2372
    } // extra parse info
}

方法3:XMLHttpRequest + Papaparse

这种方法是不使用 Input 来获取文件,直接从文件目录里面读取文件,需要使用 ajax 请求这个文件。

js 复制代码
import Papa from 'papaparse';

const readCSVFile = (filePath) => {
  if(!filePath) throw new Error('请输入正确的文件路径')
  const xhr = new window.XMLHttpRequest()
  xhr.open('GET', filePath, false)
  xhr.overrideMimeType('text/html;charset=GB2312')
  xhr.send(null)
  const { data } = Papa.parse(xhr.responseText, {
    header: true
  })
  return { data }
}

const { data } = readCSVFile('/csv/meters-mini.csv')
console.log(data, 'data-readCSVFile')

readCSVFile 的参数是 path。如果是Vue项目, 资源需要放在public文件夹下。

xhr.responseText 是字符串类型,通过 papaparse 解析,这样就可以拿到我们想要的数据结构。

方法4:使用 @rollup/plugin-dsv 插件

这个插件是基于 d3 的一个数据处理工具。github.com/d3/d3-dsv 因为图表很多涉及 csv 转换成对象的那种 Item 结构。所以 d3 直接做了一个工具。方便数据转换。

插件具体使用方法见:How do I import csv file?

链接里面也有在线 Demo,写的很清楚,这里不过多赘述。

Antv 相关

在使用比如 Antv 图表库的时候,Antv 本身提供了 csv 类型文件的解析。就不需要我们自己去解析了。比如 在 G2 的 V3 版本中使用 Connector 可以很方便的解析。

然后我去看最新的 Antv V5 版本的文档,没看到相关 Connector 里支持 csv 的说明。但通过看 G2 源码可以看到,它还是支持 csv 的。本质上还是使用的 d3-dsv 这个工具...

Antv 源码里用的挺多 d3 的插件的,好吧。这个参考很厉害...

思考

其实总结了这么多方法。实际用的时候可能没必要这么麻烦。

业务场景通常情况下的 csv 是动态数据。最好是后端来通过一个接口将 csv 返回。说到通过接口返回 csv 了,那直接一步到位返回 json 就好了,没必要在前端去处理成 json。 后端来转换的话,易于理解,方便维护 Debug。

总结这些前端处理 csv 的情况主要是为了有时候后端我们不可控,或者某些场景只有静态 csv 的时候,才去这样做。最好的方案一定不是传输 csv。

参考

JS读取本地CSV文件数据 blog.csdn.net/weixin_4397...

vue3.0中的vite如何引入markdown文件为页面 www.cnblogs.com/tyusBlog/p/...

JS读取与解析本地文本类文件 juejin.cn/post/722580...

另外,这里有一篇 How to Import a CSV Using Next.js and Node.js,其实就是:方法2:Input + Papaparse 解析 csv。

相关推荐
kyriewen11 分钟前
折腾了半年 AI 编程工作流,最后发现效率瓶颈是桌上那块屏幕
前端·javascript·ai编程
蜗牛前端38 分钟前
codex 全流程开发上线的高颜值礼簿小程序
前端·微信小程序
大龄秃头程序员1 小时前
我在图文流 App 里落地双层缓存、弱网降级与 OOM 治理
前端
老王以为1 小时前
React Renderer 分离的多平台架构
前端·react native·react.js
hunterandroid1 小时前
Kotlin Coroutines 与 Flow:让异步任务更清晰
前端
Bigger2 小时前
从零搭建 AI 代码审查服务:一份前端也能看懂的 Python 学习笔记
前端·ci/cd·ai编程
lichenyang4532 小时前
JSAPI、NAPI、Biz、Imp:ASCF Demo 如何真正调用系统能力和 C++ 能力
前端
lichenyang4533 小时前
IPC、JSVM、UIThread、libuv:ASCF 架构图里最容易混的几个词
前端
用户059540174463 小时前
Redis记忆存储故障恢复测试踩坑实录:手动测试让我漏掉了2个一致性Bug
前端·css
用户2136610035723 小时前
Vue2脚手架工程化与Axios集成
前端·vue.js