直接上代码:
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.*;
import java.util.Map.Entry;
/**
* CSV导出工具类
*/
public class CsvExportKit {
public static void main(String[] args) throws Exception {
LinkedHashMap<String, String> headerMap = new LinkedHashMap<>();
headerMap.put("key1", "字段1");
headerMap.put("key2", "字段2");
headerMap.put("key3", "字段3");
headerMap.put("key4", "字段4");
headerMap.put("key5", "字段5");
List<Map<String, String>> dataList = new ArrayList<>();
Map<String, String> item;
for (int i = 0; i < 4000000; i++) {
item = new HashMap<>();
item.put("key1", "序号" + i);
item.put("key2", "订单号2019-" + i);
item.put("key3", "2019-07-10");
item.put("key4", "300.15");
item.put("key5", "备注" + i);
dataList.add(item);
}
System.out.println("数据准备完成,开始导出......");
/*String fileName = "csv导出";
HttpServletResponse response = null;
response.setHeader("Content-disposition", "attachment; filename=" + new String(fileName.getBytes(), "ISO8859-1") + ".csv");
response.setContentType("text/csv");
response.setCharacterEncoding("UTF-8");
OutputStream out = response.getOutputStream();*/
OutputStream out = new FileOutputStream(new File("D:\\导出测试" + System.currentTimeMillis() + ".csv"));
long start = System.currentTimeMillis();
export(out, headerMap, dataList);
out.flush();
out.close();
System.out.println("导出完成, 耗时" + (System.currentTimeMillis() - start) + "毫秒!");
}
/**
* 导出CSV文件
* @param out 输出流
* @param headerMap 表头与字段对应的有序集合
* @param dataList 导出的数据
* @throws Exception
*/
public static <T> void export(OutputStream out, LinkedHashMap<String, String> headerMap, List<T> dataList) throws Exception {
String seprator = ",";
try {
// 输出表头
StringBuilder builder = new StringBuilder();
for (Entry<String, String> i : headerMap.entrySet()) {
builder.append("\"").append(i.getValue()).append("\"").append(seprator);
}
builder.append("\r");
// 输出内容
int size = dataList.size();
T data;
for (int i = 0; i < size; i++) {
for (String field : headerMap.keySet()) {
data = dataList.get(i);
builder.append("\"").append(getValue(data, field)).append("\"").append(seprator);
}
builder.append("\r");
// 每500000写入一次,防止Java heap space
if (i > 0 && (i + 1) % 500000 == 0) {
out.write(builder.toString().getBytes("GB2312"));
builder = new StringBuilder();
}
}
if (size % 500000 > 0) {
out.write(builder.toString().getBytes("GB2312"));
}
} catch (Exception e) {
throw new Exception(e.getMessage(), e);
}
}
/**
* 根据属性字段(key)获取对应属性字段(key)的值
* @param dataObj 数据对象
* @param field 字段属性(key)
* @return String 属性(key)值
*/
private static String getValue(Object dataObj, String field) {
Object value = null;
try {
if (Map.class.isAssignableFrom(dataObj.getClass())) {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) dataObj;
value = map.get(field);
} else {
Field[] fields = getFields(dataObj.getClass());
for (Field item : fields) {
item.setAccessible(true);
if (item.getName().equalsIgnoreCase(field)) {
value = item.get(dataObj);
break;
}
}
}
} catch (IllegalAccessException | IllegalArgumentException | SecurityException e) {
e.printStackTrace();
}
if (value != null) {
return String.valueOf(value);
}
return null;
}
/**
* 获取类属性字段
* @param clazz
* @return
*/
private static Field[] getFields(Class<?> clazz) {
Set<Field> fieldSet = new HashSet<>();
Field[] selfFields = clazz.getDeclaredFields();
Field[] superClassFields = clazz.getSuperclass().getDeclaredFields();
fieldSet.addAll(Arrays.asList(selfFields));
fieldSet.addAll(Arrays.asList(superClassFields));
return fieldSet.toArray(new Field[0]);
}
}另外,在本机测试时发现,当数据在400万以内时,导出很快,几秒钟完成,但是当调到500万时,导出却要耗时20多秒甚至半分钟,按数据量级倍数计算,加上其他影响,耗时应该10几秒就能完成,但事实却不是,有点不太明白,知道原因的小伙伴可以解答一下!