最近遇到了一些关于csv
文件的上传、下载、解析预览、删除的需求。因为之前没有做过,尤其是关于csv
的解析并预览,于是记录一下。
上传
关于上传,绝大部分的选择都是通过第三方的OSS
进行存储,比如阿里云的。
这个其实没什么难度,有文档可以看。对于前端来说,上传到OSS和上传给自己的后端,在过程上没什么区别,只是上传OSS
多了一些配置项的参数。
首先下载oss
的npm
包
npm install ali-oss --save
顶部进行引入
import OSS from 'ali-oss';
上传的核心代码:
const uploadFile = async (files, fileLists) => {
const fileMaxSize = 1024 * 10;
const fileType = ['csv', 'txt'];
const { originFile: { size, name } } = files[0];
const nameType = name.split('.')[1];
if (size / 1024 > fileMaxSize) {
Message('error', '文件过大!');
return;
};
if (!fileType.includes(nameType)) {
Message('error', '只支持csv和txt格式文件!');
return;
}
const ossConfig = {
region: 'oss-cn-xxxxxxx',
accessKeyId: 'xxxxxxx',
accessKeySecret: 'xxxxxxxxxx',
bucket: 'xxxxx',
};
const client = new OSS(ossConfig);
const { name: res_name, url } = await client.put(
`xxxxxx/test/${v4()}.${nameType}`,
files[0].originFile,
)
};
其实需要的参数就是ossConfig
这个对象,用来实例化引入的OSS
。
region
,这个填写的是你买的oss
资源的地区,比如oss-cn-beijing
, 就是买的中国北京地区的资源accessKeyId
、accessKeySecret
,这两个是用来鉴权需要的密钥,我是像运维要的,估计是在阿里云后台里生成的bucket
,这个是你放到的根文件夹名字,一般就是你申请资源时的主体
然后实例化出来的client
就可以直接用了,一般都是用put
方法,直接进行覆盖。传入的第一个参数是你要放到OSS
的路径,比如creator/test/xxxx.csv
,我这个名字为了避免重复,是用了一个uuid
的,需要的可以自己下一下,还是比较好用的,理论上不会重复的一段字符串。
npm install uuid --save
import { v4 } from 'uuid'
然后你就可以在返回值里拿到一系列的返回值了。
前端实现文件上传到OSS
,总体比较简单,配置一下参数之后,就跟正常的上传二进制文件一样了。
下载
下载也相对来说简单一下,先说下载,最后说预览解析。
前端实现文件的下载,其实方法比较单一,基本都是通过动态创建a
标签模拟点击来实现的。
const downloadFile = async (name, url) => {
console.log(name, url);
const result = await fetch(url);
const file = await result.blob();
let a = document.createElement('a');
let _url = window.URL.createObjectURL(file);
let filename = name;
a.href = _url;
a.download = filename;
a.style.display = 'none';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(_url);
document.body.removeChild(a);
}
因为文件是上传到了OSS
,所以前端进行下载操作的前提是,先拿到这个文件的二进制流。
先通过原生的fetch
方法请求存在OSS
的这个文件。然后通过查看原型链,可以找到这个blob
方法,将返回值转为我们需要的二进制流。
接下来的一系列操作就是通用的前端实现文件下载的代码:
- 动态创建
a
标签 - 通过
window
提供的createObjectURL
将二进制流文件转为当前域名下的一段url
- 然后将这个
url
赋值给a
标签的href
属性 - 给这个要下载的文件起一个名字赋值给
a
标签的download
属性 - 将
a
标签隐藏,放入当前文档流中(可选) - 模拟
click
事件点击 - 销毁
url
、销毁a
标签
总结下来,前端实现下载文件,其实在业务场景中很常见,实现方式也比较单一,先获取到要下载的文件二进制流、通过a
标签实现下载。
解析预览
首先,我们需要知道,csv
文件的特性,才可以进行解析。
csv
的内容其实就是形如下方的这个格式。
username, password, nickname, age,,,
creator, 123456, creator, 12,,,
xiaozhang, 123456, xiaozhang, 12,,,
所以,根据csv
文件的特点,我们就可以进行解析和展示的,展示形式一般都是表格table
。
默认情况下,我们认为csv
的第一行数据是表头,所以,我们预期是将上面这段内容转为:
[
{
username: 'creator',
password: '123456',
nickname: 'creator',
age: '12',
},
{
username: 'xiaozhang',
password: '123456',
nickname: 'xiaozhang',
age: '12',
}
]
进行数据转为的代码封装为一个函数。
const formatCSV = (str) => {
let result = [];
let jsonObj = str.split(/((\r\n)|[\r\n])+/gi);
let arrHeader = [];
for (let i in jsonObj) {
if (typeof jsonObj[i] === 'string' && jsonObj[i].length > 0) {
let row = `${jsonObj[i]}`;
if (row.trim().length > 0) {
const kv = jsonObj[i].split(',');
if (i === 0) {
arrHeader = kv;
} else {
const obj = {};
for (let index = 0; index < arrHeader.length; index ++) {
const name = String(arrHeader[index]);
if (!obj[name]) {
try {
if (kv[index]) {
obj[name] = String(kv[index]);
} else {
obj[name] = '';
}
} catch (err) {
obj[name] = '';
}
}
}
result.push(obj);
}
}
}
}
}
const previewFile = async (url) => {
const result = await fetch(url);
console.log(result);
const file = await result.blob();
const reader = new FileReader();
reader.onload = () => {
const text = reader.result;
const resultData = formatCSV(text);
setPreviewData(resultData)
setPreview(true);
};
reader.readAsText(file);
};
然后我们就可以拿到我们想要的格式的数据了。
关于表格的展示,因为我用的是react
+ antdeisgn
。
所以拼接出Table
组件需要的data
和column
即可。
data
不需要额外处理,经过我们formatCSV
返回的结果,就是我们需要的data
。
column
let column = [];
for (let i in data[0]) {
column.push({
title: i,
dataIndex: i,
})
}
<Table columns={tableColumn} data={tableData} />
ok,经过这一系列操作,就完成了我们既定的需求,关于csv
文件的上传、下载、解析预览。
总结
最近工作中做了一些没接触过的需求,总结后给大家分享一下。在此之前我甚至不知道什么是csv
的文件,只知道类似于excel
的表格。做了这个需求知道,我知道了前端上传文件到OSS、前端下载OSS的文件、csv文件的本质格式、前端解析csv文件并预览展示。 经验就是在一个个未接触过的需求中增长的。
QQ: 505417246
WX: 18331092918
公众号: Code程序人生
B站账号: LuckyRay123
个人博客: http://rayblog.ltd/
欢迎关注我的各类账号, 持续更新优质前端内容