好久没写博客了。
今天记一个java工具类的代码。(读取windows下的csv文件转为二维列表)
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Objects;
/**
* @author zzs
* @since 2022/6/12
*/
public class CSVTool {
/**
* 读带windows的BOM头的UTF-8编码csv文件
*/
public static ArrayList<ArrayList<String>> getArrayList(String fileName) {
ArrayList<ArrayList<String>> res = new ArrayList<>();
try (FileInputStream inputStream = new FileInputStream(fileName)) {
//读掉UTF-8的BOM头
inputStream.readNBytes(3);
//直接整个文件字符读到内存里
char[] csv = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8).toCharArray();
for (int i = 0; i < csv.length; i++) {
//一级迭代,每次迭代读一行
ArrayList<String> oneRow = new ArrayList<>();
for (; i < csv.length; i++) {
//二级迭代,每次迭代读一个单元格
StringBuilder oneUnitBuilder = new StringBuilder();
//分普通单元格和引号单元格两种
if (!Objects.equals(csv[i], '"')) {
//单元格开始的第一个字符不是引号,说明是普通单元格
for (; i < csv.length; i++) {
//普通三级迭代,每次迭代读普通单元格中的一个字符,非逗号或换行就直接append
if (Objects.equals(',', csv[i])
|| Objects.equals('\n', csv[i])
|| Objects.equals('\r', csv[i])) {
//读到逗号或换行则停止
break;
}
oneUnitBuilder.append(csv[i]);
}
} else {
//单元格开始的第一个字符是引号,说明是引号单元格
//读掉开头的引号
i++;
for (; i < csv.length; i++) {
//特殊三级迭代,每次迭代读引号单元格中的一个字符
if (Objects.equals('"', csv[i])) {
//如果是引号,则判断下一个字符是不是引号
if (i + 1 < csv.length && Objects.equals(csv[i + 1], '"')) {
//是连续的两个引号,则是一个转义的引号字符
oneUnitBuilder.append('"');
//读掉后面的引号
i++;
continue;
}
//不是连续的两个引号,则说明引号单元格读结束
//读掉后面的逗号(也有可能这个单元格后面没字符了,这种情况也不用担心这个自增引起溢出,因为循环都结束了)
i++;
break;
}
//不是引号的情况全都直接append
oneUnitBuilder.append(csv[i]);
}
}
oneRow.add(oneUnitBuilder.toString());
if (i < csv.length && (Objects.equals('\n', csv[i]) || Objects.equals('\r', csv[i]))) {
//读到换行或文件尾则停止
break;
}
}
if (i + 1 < csv.length && Objects.equals('\r', csv[i]) && Objects.equals('\n', csv[i + 1])) {
//杀千刀的excel保存的时候会把\n变成\r\n,因此有时要多读掉一位换行符
i++;
}
res.add(oneRow);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return res;
}
}
为什么要记这个代码呢。。主要读取csv文件这个事吧。。自己写要点时间,专门引入个依赖又显得小题大做,而且还有额外学习成本。。但自己写吧就坑也不少,所以既然花时间写了,就记录一下,说不定以后还可以用得到。