在项目开发过程中,读取excel文件,可能存在几百或几百万条数据内容,那么对于大型文件来说,我们应该如何思考对于大型文件的读取操作以及性能的注意事项。
类库:Papa Parse - Powerful CSV Parser for JavaScript
第一步:安装
npm install papaparse
第二步:内容的引入
import Papa from 'papaparse';import { useState } from "react";export default function App() { const [results,setResults] = useState([]); //保留解析后的数据 const handleFile = (e) => { const file = e.target.files[0]; Papa.parse(file,{ header:true, //指定第一行为标题行 skipEmptyLines:true, //跳过空行 complete:(parsedResult) => { const data = parsedResult.data; console.log(data) // 在控制台打印解析后的数据 } }) }; return ( <div> <h1>本地读取Excel文件并进行数据压缩传递到服务器</h1> <input type="file" onChange={handleFile} accept='.csv' /> </div> )}
当我们上传的数据为百万条数据的时候,数据量是非常的庞大的,那么如果将数据传输到服务器上,将会对http的请求资源产生极大的浪费。所以我们考虑使用第三方类库pako进行数据的压缩。
对于pako,可以查看以下文章进行一个了解:https://github.com/nodeca/pako
pako是什么以及它的的使用_如何使用pako库-CSDN博客文章浏览阅读62次。ws推送的gzip压缩能减少大量的传输数据,减少传输数据消耗,但是需要在收到数据之后解压。解压就可以用到pako了。_如何使用pako库https://blog.csdn.net/mantou_riji/article/details/135001065
%20第三步:pako安装
%20npm%20install%20pako
%20第四步:在组件中进行pako引入且对数据进行gzip的压缩
%20import%20pako%20from%20"pako";
%20引入之后,将我们获取到的数据进行gzip的压缩
%20//%20gzip压缩const%20gzip%20=%20pako.gzip(JSON.stringify(data),{to:"string"});console.log(JSON.stringify(data).length,gzip.length);%20//打印的则是压缩后的数据信息//原先的长度为41万,压缩后的长度为4万
%20且发送到后端(以下是改事件的全部代码,gzip的压缩数据也在其内)
%20%20const%20handleFile%20=%20(e)%20=>%20{%20%20%20%20%20%20%20%20const%20file%20=%20e.target.files[0];%20%20%20%20%20%20%20%20Papa.parse(file,{%20%20%20%20%20%20%20%20%20%20%20%20header:true,%20//指定第一行为标题行%20%20%20%20%20%20%20%20%20%20%20%20skipEmptyLines:true,%20//跳过空行%20%20%20%20%20%20%20%20%20%20%20%20complete:async%20(parsedResult)%20=>%20{%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20data%20=%20parsedResult.data;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20console.log(data)%20//%20在控制台打印解析后的数据%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20gzip压缩%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20gzip%20=%20pako.gzip(JSON.stringify(data),{to:"string"});%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20console.log(JSON.stringify(data).length,gzip.length);%20//打印的则是压缩后的数据信息%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20response%20=%20await%20fetch("http://localhost:3000",{%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20method:"POST",%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20body:gzip,%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20headers:{%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20"Content-Type":"application/octet-stream",%20//数据流的方式进行上传处理%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20}%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20});%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20console.log(response)%20%20%20%20%20%20%20%20%20%20%20%20}%20%20%20%20%20%20%20%20})%20%20%20%20};
%20第五步:后端,后端也需要下载pako进行解压缩处理
%20const%20express%20=%20require("express");const%20bodyParser%20=%20require("body-parser");const%20cors%20=%20require("cors");const%20pako%20=%20require("pako");const%20app%20=%20express();//%20使用%20cors%20中间件处理跨域请求app.use(cors());//%20使用%20bodyParser%20中间件解析请求体app.use(bodyParser.raw({%20type:%20"application/octet-stream",%20limit:%20"100mb"%20}));//%20处理%20POST%20请求app.post("/",%20(req,%20res)%20=>%20{%20%20//%20获取压缩后的数据%20%20const%20compressedData%20=%20req.body;%20%20//%20解压缩数据%20%20const%20uncompressedData%20=%20pako.ungzip(compressedData,%20{%20to:%20"string"%20});%20%20//%20将解压缩后的数据解析为%20JSON%20对象%20%20const%20jsonData%20=%20JSON.parse(uncompressedData);%20%20//%20打印压缩前数据长度,解压缩后数据长度和%20JSON%20对象长度%20%20console.log(%20%20%20%20compressedData.length,%20%20%20%20uncompressedData.length,%20%20%20%20jsonData.length%20%20);%20%20//%20构造响应消息%20%20const%20msg%20=%20%20%20%20compressedData.length%20+%20%20%20%20"%20"%20+%20%20%20%20uncompressedData.length%20+%20%20%20%20"%20"%20+%20%20%20%20jsonData.length;%20%20//%20发送响应%20%20res.status(200).send(msg);});//%20启动服务器,监听端口%203000app.listen(3000,%20()%20=>%20{%20%20console.log("Server%20started%20on%20port%203000");});
%20执行以上操作后,我们运行项目选择文件,后端返回三条数据
%20已压缩的长度 %20 未压缩的长度 %20 最终记录的条数
%20前端也已经返回了response的一个相应数据
第六步:对打印的response进行进一步的处理
console.log(response)const result = { success:response.ok.toString(), status:response.status, message:response.statusText,};setResults(result)
第七步:展示到页面上
<h2>结果显示</h2><ul> {results && Object.keys(results).map((key) => { <li key={key}> {key}:{results[key]} </li> }) }</ul>
第八步:添加一个点击按钮事件切换背景颜色
const toggleBodyBackground = () => { if(document.body.style.background === "red"){ document.body.style.background = "white"; }else{ document.body.style.background = "red" }}<button onClick={toggleBodyBackground}>change body background</button>
当我进行大文件读取的时候会造成主线程的阻塞,那么后续我们可以进行功能的强化,在强化过程中,我们可以去考虑,是不是可以对现有的数据进行拆分,如果是一百多万条数据的时候,我们可以将一百多万条数据进行五万条,五万条的切片处理,然后不断的在后端进行压缩后数据的请求处理,最终可以在服务器端进行对数据的操作,减轻服务器的压力。
第九步:是否可以减轻服务器的压力,以下操作可以进行一个测试
使用console.time('test')开始时间设置和console.timeEnd("test")结束时间设置
const handleFile = (e) => { console.time('test') //开始时间 const file = e.target.files[0]; Papa.parse(file,{ ............... }; setResults(result) console.timeEnd("test"); //结束时间 } })};
当前的测试时间为18秒左右,耗费时常比较久,那么随后我们会对其进行功能优化处理。
此内容已结束,希望对您有所帮助。