一、简述
日常开发中,把数据做成表格输出和导出非常常见。那表格输出有Excel格式(例如 xx.xlsx),也有最简单的CSV格式。对比常见的Excel格式的表格,CSV的导入导出不需要增加额外依赖,全平台通用,适合于数据结构简单、快速开发和大数据场景。
二、CSV文件的读取
上代码
/**
* CSV文件读取
* @param file 文件,包含完整路径
* @param charset 文件编码
* @return 读取的结果集
*/
public static List<List<String>> read(String file, Charset charset) {
List<List<String>> res = new ArrayList<>();
try (FileInputStream inputStream = new FileInputStream(file); BufferedReader sc = new BufferedReader(new InputStreamReader(inputStream, charset))) {
String line;
while ((line = sc.readLine()) != null) {
res.add(handleCSVString(line));
}
} catch (IOException ignored) {
}
return res;
}
/**
* 处理读取到的字符串
* @param string 字符串
* @return 解析后的数据
*/
private static List<String> handleCSVString(String string) {
List<String> res = new ArrayList<>();
StringBuilder stringBuilder = new StringBuilder();
int start = 0;
boolean escape = false;
while (start < string.length()) {
char ch = string.charAt(start ++);
switch (ch) {
case ',':
if (!escape) {
res.add(handleSplitString(stringBuilder));
stringBuilder = new StringBuilder();
} else {
stringBuilder.append(ch);
}
break;
case '"':
if (escape) {
stringBuilder.append(ch);
escape = false;
} else {
escape = true;
}
break;
default:
stringBuilder.append(ch);
break;
}
}
res.add(handleSplitString(stringBuilder));
return res;
}
/**
* 处理分割后的字符串,去除双引号
* @param stringBuilder 字符串
* @return 处理结果
*/
private static String handleSplitString(StringBuilder stringBuilder) {
String str = stringBuilder != null ? stringBuilder.toString() : "";
if (!str.isEmpty() && str.charAt(str.length() - 1) == '"') {
str = str.substring(0, str.length() - 1);
}
return str;
}
注意点:
1、字符编码
2、逗号和双引号对于CSV而言是特殊字符,含有逗号和双引号的字符串需要做转义
三、CSV文件的写入
上代码
/**
* 写文件
* @param dataList 数据集
* @param file 文件,包含完整路径
* @param charset 文件字符编码
* @return 结果
*/
public static boolean write(List<List<String>> dataList, String file, Charset charset) {
boolean isSuccess = false;
try (OutputStream fileOutStream = new FileOutputStream(file);
OutputStreamWriter fileOutStreamWriter = new OutputStreamWriter(fileOutStream, charset);
BufferedWriter fileWriter = new BufferedWriter(fileOutStreamWriter)) {
for (List<String> strs : dataList) {
fileWriter.write(handleToCSVString(strs));
fileWriter.newLine();
}
isSuccess = true;
} catch (IOException ignored) {
}
return isSuccess;
}
/**
* 处理每行数据
* @param strings 数据
* @return CSV格式的字符串
*/
private static String handleToCSVString(List<String> strings) {
if (strings == null || strings.isEmpty()) {
return "";
}
StringBuilder newStr = new StringBuilder();
for (String ss : strings) {
if (ss.contains(",") || ss.contains("\"")) {
newStr.append(escapeCSVString(ss)).append(",");
} else {
newStr.append(ss).append(",");
}
}
return newStr.toString().substring(0, newStr.length() - 1);
}
/**
* 转义CSV字符串:双引号做特殊处理
* @param string 要转义的字符串
* @return 转义后结果
*/
private static String escapeCSVString(String string) {
StringBuilder res = new StringBuilder();
res.append('"');
int index = 0;
while (index < string.length()) {
char ch = string.charAt(index++);
if (ch == '"') {
res.append('"').append('"');
} else {
res.append(ch);
}
}
res.append('"');
return res.toString();
}
注意文件的编码,如果有乱码,检查一下编码是否一致