这两天需要做一个将CSV文件内容上传至数据库中,进行持久化,我的思路是先进行读取出来,然后进行一行一行插入数据库中。这种思路目前来说可能没问题,因为涉及的数据较少,如果涉及较多的数据可能就会出现加载过慢的问题,那么就需要做代码优化。
我的CSV文件是通过爬虫从第三方数据库中爬取得到的,里面的内容格式也是各种各样。因为自己还年轻,就直接想到了以流的形式进行读取。代码如下:
InputStreamReader isr = new InputStreamReader(new FileInputStream(path), "UTF-8");
BufferedReader reader = new BufferedReader(isr);
int i = 0;
int a = 0;
try {
String line = null;
while((line=reader.readLine())!=null){
String[] item = line.split(",",-1);//CSV格式文件为逗号分隔符文件,这里根据逗号切分
System.out.println("长度:"+item.length);
String str = item[1];
//item[1]为价格,且为字符串,将字符串中的小数进行提取出来
// 控制正则表达式的匹配行为的参数(小数)
Pattern p = Pattern.compile("(\\d+\\.\\d+)");
//Matcher类的构造方法也是私有的,不能随意创建,只能通过Pattern.matcher(CharSequence input)方法得到该类的实例.
Matcher m = p.matcher(str);
//m.find用来判断该字符串中是否含有与"(\\d+\\.\\d+)"相匹配的子串
if (m.find()) {
//如果有相匹配的,则判断是否为null操作
//group()中的参数:0表示匹配整个正则,1表示匹配第一个括号的正则,2表示匹配第二个正则,在这只有一个括号,即1和0是一样的
str = m.group(1) == null ? "" : m.group(1);
} else {
//如果匹配不到小数,就进行整数匹配
p = Pattern.compile("(\\d+)");
m = p.matcher(str);
if (m.find()) {
//如果有整数相匹配
str = m.group(1) == null ? "" : m.group(1);
} else {
//如果没有小数和整数相匹配,即字符串中没有整数和小数,就设为空
str = "";
}
}
System.out.println("我是:"+str);
DataInfo dataInfo=new DataInfo();
System.out.println("item的长度:"+item.length);
//将英文逗号转换成中文逗号
System.out.println("原始名字:"+item[0]);
String b = ",";
String str0 = item[0].replaceAll(",",b);
System.out.println("item[0]:"+str0);
System.out.println("item[1]:"+str);
System.out.println("item[2]:"+item[2]);
System.out.println("item[3]:"+item[3]);
if (item[2].length() == 0){
item[2] = "0";
}
if (item[3].length() == 0){
item[3] = "0";
}
if (str.length() == 0){
str = "0";
}
dataInfo.setName(str0);
dataInfo.setPrice(str);
dataInfo.setLatitude(item[2]);
dataInfo.setLongitude(item[3]);
dataInfo.setCreateDate(current);
System.out.println("DataInfo的值:"+dataInfo);
String[] split = fileName.split("-");
System.out.println("split444:"+split[1]);
//取第二个值
if (split[1].equals("newhouse")){
System.out.println("hahahaha1111");
i = intoMapper.intoNewsMapper(dataInfo);
a=a+1;
}else if (split[1].equals("secondhouse")){
i = intoMapper.intoSecondMapper(dataInfo);
a=a+1;
}else if (split[1].equals("rentinghouse")){
i = intoMapper.intoRentMapper(dataInfo);
a=a+1;
}
}
}finally {
reader.close();
}
大致思路就是通过InputStreamReader isr = new InputStreamReader(new FileInputStream(path), "UTF-8");
BufferedReader reader = new BufferedReader(isr)
以流的形式进行全部读取,然后再通过循环行line=reader.readLine()
进行遍历出来,然后再进行将每行的数据分割出来,插入到数据库中。问题就出现在行分割上面,因为是通过爬虫从第三方爬取出来的数据,格式完全不一样,有换行啦,有英文逗号啦,反正就是不可预测的各种格式,本身没办法预测更不要说进行处理这些数据了。当遇到换行问题时还好进行处理,遇到从一段文字中提取出来小数或者整数的时候也好进行处理,最难的是遇到英文逗号“,”
了是最难处理的,英文你读取的数据本身每一列隔开就是用英文逗号分割开来的,读取后的内容如下图所示:
整租·山海梧桐 1室1厅 南/北,2750 元/月,22.561189,114.2286
整租·鸿荣源·壹城中心第八区 1室1厅 南,1820 元/月,22.6527136689,114.0360039841
整租·龙光玖云著 2室1厅 南,2800 元/月,22.685514,114.337256
整租·共和花园 1室0厅 南,1350 元/月,22.654156577768,114.04290481474
整租·茂业城 1室1厅 东南,1800 元/月,22.617428,114.140558
整租·向南一区 1室0厅 东南,1699 元/月,22.628218357484,114.04349583641
整租·锦城星苑 2室1厅 北,2200 元/月,22.751925445789,114.2864754459
整租·光明1号 4室2厅 东南,3000 元/月,22.740888,113.935798
整租·财富城 3室2厅 东南,2000 元/月,22.708919,114.346404
整租·百合盛世二期 3室1厅 西北,1800 元/月,22.750213,114.244653
整租·麓园 4室2厅 东南,2000 元/月,22.73853,114.22597
整租·军裕公寓 1室0厅 东,1980 元/月,22.601874,113.855116
整租·宏发雍景城 2室2厅 南/北,3800 元/月,22.785978,113.912478
整租·元芬花园 1室0厅 东南/南/西南,1299 元/月,22.660840985621,114.00942180444
整租·奥园峯荟 2室2厅 复式 西南,3200 元/月,22.771239,113.904964
整租·又一城 2室2厅 东南/南,1800 元/月,22.731801,114.220185
整租·茂业城 1室0厅 西北,1800 元/月,22.617428,114.140558
整租·茂业城 1室1厅 东南,2000 元/月,22.617428,114.140558
合租·深业新岸线三期 1居室 西南卧,1900 元/月,22.565182,113.879114
整租·德兴城花园 1室1厅 南/西南,2300 元/月,22.614861,114.120201
合租·麟恒中心广场一期 3居室 东南卧,1700 元/月,22.643806,114.19315
你看文件内容中有英文逗号,读取的内容列于列之间又是通过“,”
进行分割的,你也不知道文件内容中何时出来英文逗号。当时第一反应是把所有的内容中的逗号全部replaceAll()
替换为中文逗号,但是你要直接替换,那就出现把列与列之间的英文逗号也进行替换,因此不可行;当时想到先进行分割进行替换,写了之后还进行报错,最后想起来分割后替换已经晚了,因为文件内容中的英文逗号已经进行分割,所以这种方式还是失败的。最后问了老大,给了个思路,利用fastCSV工具进行读取文件。
下面讲下怎么使用fastCSV这个工具:
首先导入fastCSV依赖:
<dependency>
<groupId>de.siegmar</groupId>
<artifactId>fastcsv</artifactId>
<version>1.0.3</version>
</dependency>
然后是代码实现
CsvReader csvReader = new CsvReader();
CsvReader fileReader = new CsvReader();
CsvContainer csvFile = fileReader.read(file, Charset.forName("UTF-8"));
if(csvFile!=null){
for (CsvRow rowfiles : csvFile.getRows()) {
String str = rowfiles.getField(1);
//item[1]为价格,且为字符串,将字符串中的小数进行提取出来
// 控制正则表达式的匹配行为的参数(小数)
Pattern p = Pattern.compile("(\\d+\\.\\d+)");
//Matcher类的构造方法也是私有的,不能随意创建,只能通过Pattern.matcher(CharSequence input)方法得到该类的实例.
Matcher m = p.matcher(str);
//m.find用来判断该字符串中是否含有与"(\\d+\\.\\d+)"相匹配的子串
if (m.find()) {
//如果有相匹配的,则判断是否为null操作
//group()中的参数:0表示匹配整个正则,1表示匹配第一个括号的正则,2表示匹配第二个正则,在这只有一个括号,即1和0是一样的
str = m.group(1) == null ? "" : m.group(1);
} else {
//如果匹配不到小数,就进行整数匹配
p = Pattern.compile("(\\d+)");
m = p.matcher(str);
if (m.find()) {
//如果有整数相匹配
str = m.group(1) == null ? "" : m.group(1);
} else {
//如果没有小数和整数相匹配,即字符串中没有整数和小数,就设为空
str = "";
}
}
String a2 = rowfiles.getField(2);
String a3 = rowfiles.getField(3);
if (rowfiles.getField(2).length() == 0){
a2 = "0";
}
if (rowfiles.getField(3).length() == 0){
a3 = "0";
}
if (str.length() == 0){
str = "0";
}
DataInfo dataInfo=new DataInfo();
dataInfo.setName(rowfiles.getField(0));
dataInfo.setPrice(str);
dataInfo.setLatitude(a2);
dataInfo.setLongitude(a3);
String[] split = fileName.split("-");
//取第二个值
if (split[1].equals("newhouse")){
i = intoMapper.intoNewsMapper(dataInfo);
a=a+1;
}else if (split[1].equals("secondhouse")){
i = intoMapper.intoSecondMapper(dataInfo);
a=a+1;
}else if (split[1].equals("rentinghouse")){
i = intoMapper.intoRentMapper(dataInfo);
a=a+1;
}
}
}
上面是我的代码,下面给大家介绍一下使用它的三种方式:
第一种:
public static List<ResultInfo> csvReadOperation() throws IOException {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
String dateString = formatter.format(currentTime);
System.out.println("startTime:"+dateString);
File file = new File("/Users/xxx/Desktop/testCSVReader.csv");
CsvReader csvReader = new CsvReader();
csvReader.setContainsHeader(true); //表示文件包含表头
List<ResultInfo> listResultInfo = new ArrayList<>();
CsvContainer csv = csvReader.read(file, StandardCharsets.UTF_8);
for (CsvRow row : csv.getRows()) {
if (row.getOriginalLineNumber() != 1) { //同样是为了去掉表头
ResultInfo resultInfo = new ResultInfo();
resultInfo.setUserId(row.getField(0));
resultInfo.setUserPhone(row.getField(1));
resultInfo.setUserName(row.getField(2));
resultInfo.setRegistTime(row.getField(3));
resultInfo.setUserlevel(row.getField(4));
resultInfo.setAppName(row.getField(5));
listResultInfo.add(resultInfo);
}
}
return listResultInfo;
}
第二种方式:有时候文件中包含空行,如果想跳过空行,需要设置属性
public static List<ResultInfo> csvReadOperation1() throws IOException {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
String dateString = formatter.format(currentTime);
System.out.println("startTime:"+dateString);
File file = new File("/Users/fengyanjie/Desktop/test1CSVReader.csv");
CsvReader csvReader = new CsvReader();
csvReader.setContainsHeader(true);
csvReader.setSkipEmptyRows(true);//设置跳过空行
CsvContainer csv = csvReader.read(file, StandardCharsets.UTF_8);
List<ResultInfo> listResultInfo = new ArrayList<>();
System.out.println("文件list大小:"+csv.getRows().size());
for (CsvRow row : csv.getRows()) {
if (row.getOriginalLineNumber() != 1 && "" !=row.getFields().get(0)) {
ResultInfo resultInfo = new ResultInfo();
resultInfo.setUserId(row.getField(0));
resultInfo.setUserPhone(row.getField(1));
resultInfo.setUserName(row.getField(2));
resultInfo.setRegistTime(row.getField(3));
resultInfo.setUserlevel(row.getField(4));
resultInfo.setAppName(row.getField(5));
listResultInfo.add(resultInfo);
}
}
return listResultInfo;
}
第三种:
public static List<ResultInfo> csvReadOperation2() throws IOException {
Date currentTime = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
String dateString = formatter.format(currentTime);
System.out.println("startTime:"+dateString);
File file = new File("/Users/fengyanjie/Desktop/test1CSVReader.csv");
CsvReader csvReader = new CsvReader();
List<ResultInfo> listResultInfo = new ArrayList<>();
try (CsvParser csvParser = csvReader.parse(file, StandardCharsets.UTF_8)) {
CsvRow row;
while ((row = csvParser.nextRow()) != null) {
ResultInfo resultInfo = new ResultInfo();
resultInfo.setUserId(row.getField(0));
resultInfo.setUserPhone(row.getField(1));
resultInfo.setUserName(row.getField(2));
resultInfo.setRegistTime(row.getField(3));
resultInfo.setUserlevel(row.getField(4));
resultInfo.setAppName(row.getField(5));
listResultInfo.add(resultInfo);
}
}
return listResultInfo ;
}
生成CSV文件:
不罗嗦了直接上代码:
//指定路径和编码
CsvWriter writer = CsvUtil.getWriter("e:/testWrite.csv", CharsetUtil.CHARSET_UTF_8);
//按行写出
writer.write(
new String[] {"a1", "b1", "c1"},
new String[] {"a2", "b2", "c2"},
new String[] {"a3", "b3", "c3"}
);
效果如下: