前言
从华为云oss读取csv文件时发现解析数据时与源数据条数对不上,数据解析错乱
一、问题现象
1.问题代码
URL url = new URL(req.getOssUrl());
InputStream inputStream = url.openConnection().getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(reader, IoUtil.DEFAULT_BUFFER_SIZE);
// 源数据有502条,却解析成520条
List<JSONObject> jsonObjects = CsvUtil.getReader().read(bufferedReader, JSONObject.class);
2.问题现象
debug发现解析的数据与源数据对不上,且源数据有,字符被提前分割了(csv文件每列以,号分割)
二、问题分析
1.hutool工具是怎么解析一行的
有问题的那行数据,有\n字符,在解析时被认为这是另一行被提前分割了,def roundfun(i0,j0,n,m,num): 字符就认为是一行的数据,再以逗号分隔为每列的数据,最终看到一行的数据就是def roundfun(i0 j0 n m num这几列,显然这样解析不对
看CsvConfig源码是以,号为每个字段(列)为分割符,但是源数据里的是第一列包括了逗号被提前分割了
2.怎么解决\n符呢?
1、看hutool工具源码有设置字段分割符CsvConfig.setFieldSeparator(fieldSeparator)。但是现在的问题是怎么忽略\n这种正常换行字符和字段分割符(,号)无关,hutool工具没有对应的设置类。
2、查资料opencsv可以解决此类问题
三、解决方案(opencsv解析)
1.maven配置
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.5</version>
</dependency>
2.代码修改
URL url = new URL(req.getOssUrl());
InputStream inputStream = url.openConnection().getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(reader, IoUtil.DEFAULT_BUFFER_SIZE);
List<JSONObject> jsonObjects = readCsv(bufferedReader);
/**
* 读取csv格式文件
* @param reader
* @return
*/
private List<JSONObject> readCsv(Reader reader) {
// 忽略\n换行字符,避免同一行的数据被分割
CSVReader csvReader = new CSVReader(reader, ',', '"', '\n');
Iterator<String[]> iterator = csvReader.iterator();
boolean head = true;
// 表头
List<String> headList = null;
List<JSONObject> jsonObjects = Lists.newArrayList();
while (iterator.hasNext()) {
String[] next = iterator.next();
if (head) {
head = false;
headList = Lists.newArrayList(next);
continue;
}
JSONObject jsonObject = convertJson(next, headList);
jsonObjects.add(jsonObject);
}
try {
// 要把对应流关闭
csvReader.close();
} catch (IOException e) {
log.error("read bi callback csv failed!", e);
}
return jsonObjects;
}
看CSVReader默认是忽略\字符,但我们需要忽略\n字符,因此定义为CSVReader csvReader = new CSVReader(reader, ‘,’, ‘"’, ‘\n’);
总结
1、csv文件有\n换行字符解析可能会错乱,可通过opencsv包CSVReader csvReader = new CSVReader(reader, ‘,’, ‘"’, ‘\n’);解决,也可自行处理
2、测试文件:https://csdn-bi-data.obs.cn-north-4.myhuaweicloud.com:443/xongkoro/download/tmp_odps_download_41291366e907423c9733737533345ffa/part-00000-589afb42-3310-40b3-9dad-1f11e317db01-c000.csv?AccessKeyId=IR5RUNOTFAJTRVVHR9KN&Expires=1691549909&Signature=XR7oeAbTem22yHjoqvWZUIPhOJ8%3D